Skip to content
Commits on Source (7)
trollsched/version.py export-subst
......@@ -31,6 +31,16 @@ script: coverage run --source=trollsched setup.py test
after_success:
- if [[ $PYTHON_VERSION == 3.6 ]]; then coveralls; fi
#
deploy:
- provider: pypi
user: adybbroe
password:
secure: SY0qo7sZXDjDx0DHvuXrHvL9VTAulgU/T33d6UWXf469jT9DOexuZ2VYLgJbYQen5FSe5JmQE0ZMdId1cb8IPP/77qCgQK6f0lRDa43fSYXhcD+fHzlQskievJrwamkRYx6WBrJbwGAKBNinUgNSaTdbh9XUugziGFiOHUfVppM=
distributions: sdist
skip_existing: true
on:
tags: true
repo: pytroll/pytroll-schedule
notifications:
slack:
rooms:
......
## Version <RELEASE_VERSION> (2018/11/25)
## Version 0.5.1 (2019/01/08)
### Issues Closed
* [Issue 27](https://github.com/pytroll/pytroll-schedule/issues/27) - Drawing the ascat outline
* [Issue 25](https://github.com/pytroll/pytroll-schedule/issues/25) - New version slower in generating the schedule ([PR 26](https://github.com/pytroll/pytroll-schedule/pull/26))
In this release 2 issues were closed.
### Pull Requests Merged
#### Bugs fixed
* [PR 26](https://github.com/pytroll/pytroll-schedule/pull/26) - Speed up schedule generation ([25](https://github.com/pytroll/pytroll-schedule/issues/25))
* [PR 24](https://github.com/pytroll/pytroll-schedule/pull/24) - Bugfix schedule generation
#### Features added
* [PR 29](https://github.com/pytroll/pytroll-schedule/pull/29) - Move save_fig import in under the save function
* [PR 28](https://github.com/pytroll/pytroll-schedule/pull/28) - Restructure the get_next_passes putting some of the highly nested cod…
* [PR 26](https://github.com/pytroll/pytroll-schedule/pull/26) - Speed up schedule generation ([25](https://github.com/pytroll/pytroll-schedule/issues/25))
* [PR 23](https://github.com/pytroll/pytroll-schedule/pull/23) - Versioneer
In this release 6 pull requests were closed.
## Version 0.5.0 (2018/11/25)
### Issues Closed
......
include versioneer.py
include trollsched/version.py
pytroll-schedule
================
Reception scheduling of polar weather satellites
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/9f039d7d640846ca89be8a78fa11e1f6)](https://www.codacy.com/app/adybbroe/pytroll-schedule?utm_source=github.com&utm_medium=referral&utm_content=pytroll/pytroll-schedule&utm_campaign=badger)
[![Build Status](https://travis-ci.org/pytroll/pytroll-schedule.png?branch=master)](https://travis-ci.org/pytroll/pytroll-schedule)
[![Coverage Status](https://coveralls.io/repos/github/pytroll/pytroll-schedule/badge.svg?branch=master)](https://coveralls.io/github/pytroll/pytroll-schedule?branch=master)
[![Code Health](https://landscape.io/github/pytroll/pytroll-schedule/master/landscape.png)](https://landscape.io/github/pytroll/pytroll-schedule/master)
[![PyPI version](https://badge.fury.io/py/pytroll-schedule.svg)](https://badge.fury.io/py/pytroll-schedule)
Reception scheduling of polar orbiting weather satellites
# Releasing pytroll-schedule
1. checkout master
2. pull from repo
3. run the unittests
4. run `loghub` and update the `CHANGELOG.md` file:
```
loghub pytroll/pytroll-schedule -u <username> -st v0.5.0 -plg bug "Bugs fixed" -plg enhancement "Features added" -plg documentation "Documentation changes"
```
Don't forget to commit!
5. Create a tag with the new version number, starting with a 'v', eg:
```
git tag v0.5.1 -m "Version 0.5.1"
```
See [semver.org](http://semver.org/) on how to write a version number.
6. push changes to github `git push --follow-tags`
7. Verify travis tests passed and deployed sdist and wheel to PyPI
pytroll-schedule (0.5.1-1) unstable; urgency=medium
* New upstream release.
* debian/control:
- update package description
* debian/copyright:
- update copyright dates
- new entry for versioneer.py
* debian/patches:
- refresh all patches
-- Antonio Valentino <antonio.valentino@tiscali.it> Thu, 10 Jan 2019 07:27:18 +0000
pytroll-schedule (0.5.0-1) unstable; urgency=medium
* Initial version (Closes: #917219)
......
......@@ -28,7 +28,7 @@ Recommends: trollsched-bin,
Suggests: ${python3:Suggests}
Description: Scheduling satellite passes in Python
The package provides a Python library and tools for reception
scheduling of polar weather satellites.
scheduling of polar orbit weather satellites.
This package is part of the PyTroll software suite.
Package: trollsched-bin
......@@ -41,7 +41,7 @@ Recommends: ${python3:Recommends}
Suggests: ${python3:Suggests}
Description: Scheduling satellite passes in Python - scripts
The package provides a Python library and tools for reception
scheduling of polar weather satellites.
scheduling of polar orbit weather satellites.
This package is part of the PyTroll software suite.
.
This package provides utilities and executable scripts.
......@@ -4,12 +4,17 @@ Upstream-Contact: Martin Raspaud <martin.raspaud@smhi.se>
Source: https://github.com/pytroll/pytroll-schedule
Files: *
Copyright: 2013-2018 Martin Raspaud
2014-2018 PyTroll Community
2016, 2018 Adam.Dybbroe
Copyright: 2013-2019 PyTroll
2013-2018 Martin Raspaud
2014-2019 PyTroll Community
2016, 2018 Adam Dybbroe
2017-2018 Alexander Maul
License: GPL-3+
Files: versioneer.py
Copyright: 2018, Brian Warner
License: CC0-1.0
Files: debian/*
Copyright: 2018 Antonio Valentino <antonio.valentino@tiscali.it>
License: GPL-3+
......@@ -30,3 +35,14 @@ License: GPL-3+
.
On Debian systems, the complete text of the GNU General
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
License: CC0-1.0
To the extent possible under law, the author(s) have dedicated all copyright
and related and neighboring rights to this software to the public domain
worldwide. This software is distributed without any warranty.
.
You should have received a copy of the CC0 Public Domain Dedication along with
this software. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
.
On Debian systems, the complete text of the CC0 1.0 Universal license can be
found in ‘/usr/share/common-licenses/CC0-1.0’.
......@@ -8,10 +8,10 @@ Subject: Fix tests
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/setup.py b/setup.py
index a8a909d..ec6127e 100644
index a08755b..1d05671 100644
--- a/setup.py
+++ b/setup.py
@@ -58,7 +58,7 @@ setup(name='pytroll-schedule',
@@ -56,7 +56,7 @@ setup(name='pytroll-schedule',
'compare_scheds = trollsched.compare:run']},
scripts=['generate_schedule_xmlpage.py'],
packages=['trollsched'],
......
......@@ -7,10 +7,10 @@ Subject: Do not install broken script
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup.py b/setup.py
index ec6127e..a679272 100644
index 1d05671..3d84a2d 100644
--- a/setup.py
+++ b/setup.py
@@ -56,7 +56,7 @@ setup(name='pytroll-schedule',
@@ -54,7 +54,7 @@ setup(name='pytroll-schedule',
entry_points={
'console_scripts': ['schedule = trollsched.schedule:run',
'compare_scheds = trollsched.compare:run']},
......
[bdist_rpm]
requires=numpy pyresample pyorbital
release=1
# See the docstring in versioneer.py for instructions. Note that you must
# re-run 'versioneer.py setup' after changing this section, and commit the
# resulting files.
[versioneer]
VCS = git
style = pep440
versionfile_source = trollsched/version.py
versionfile_build =
tag_prefix = v
parentdir_prefix =
[bdist_wheel]
universal=1
[flake8]
max-line-length = 120
[coverage:run]
omit =
trollsched/version.py
versioneer.py
......@@ -25,12 +25,9 @@
"""
# workaround python bug: http://bugs.python.org/issue15881#msg170215
import multiprocessing
from setuptools import setup
import imp
import sys
version = imp.load_source('trollsched.version', 'trollsched/version.py')
import versioneer
requires = ['numpy', 'pyresample', 'pyorbital']
test_requires = ['satpy']
......@@ -40,7 +37,8 @@ if sys.version_info < (2, 7):
requires.append('argparse')
setup(name='pytroll-schedule',
version=version.__version__,
version=versioneer.get_version(),
cmdclass=versioneer.get_cmdclass(),
description='Scheduling satellite passes in Python',
author='Martin Raspaud',
author_email='martin.raspaud@smhi.se',
......
......@@ -23,6 +23,11 @@
"""Package file.
"""
from .version import get_versions
__version__ = get_versions()['version']
del get_versions
# shortest allowed pass in minutes
MIN_PASS = 4
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2014-2018 PyTroll community
# Copyright (c) 2014-2019 PyTroll community
# Author(s):
......@@ -35,6 +35,9 @@ from pyorbital import geoloc, geoloc_instrument_definitions
logger = logging.getLogger(__name__)
INSTRUMENT = {'avhrr/3': 'avhrr',
'avhrr/2': 'avhrr'}
class SwathBoundary(Boundary):
......@@ -50,24 +53,30 @@ class SwathBoundary(Boundary):
# cheating at the moment.
# scan_angle = 55.37
if instrument == "modis":
# scan_angle = 55.0
scan_angle = 55.0
instrument = "avhrr"
elif instrument == "viirs":
# scan_angle = 55.84
scan_angle = 55.84
instrument = "viirs"
elif instrument == "iasi":
# scan_angle = 48.3
scan_angle = 48.3
instrument = "avhrr"
elif overpass.satellite == "noaa 16":
# scan_angle = 55.25
scan_angle = 55.25
instrument = "avhrr"
else:
# scan_angle = 55.25
elif instrument == "mersi2":
scan_angle = 55.4
instrument = "avhrr"
else:
scan_angle = 55.25
instrument_fun = getattr(geoloc_instrument_definitions, instrument)
instrument_fun = getattr(geoloc_instrument_definitions, INSTRUMENT.get(instrument, instrument))
if instrument in ["olci", "avhrr", "ascat", "avhrr/3", "avhrr/2"]:
if instrument in ["avhrr", "avhrr/3", "avhrr/2"]:
sgeom = instrument_fun(scans_nb, scanpoints, scan_angle=scan_angle, frequency=100)
elif instrument in ["ascat", ]:
sgeom = instrument_fun(scans_nb, scanpoints)
elif instrument in ["olci", ]:
sgeom = instrument_fun(scans_nb, scanpoints)
elif instrument == 'viirs':
sgeom = instrument_fun(scans_nb, scanpoints, scan_step=scan_step)
......@@ -86,7 +95,7 @@ class SwathBoundary(Boundary):
return (lons.reshape(-1, len(scanpoints)),
lats.reshape(-1, len(scanpoints)))
def __init__(self, overpass, scan_step=20, frequency=100):
def __init__(self, overpass, scan_step=50, frequency=200):
# compute area covered by pass
Boundary.__init__(self)
......@@ -102,20 +111,26 @@ class SwathBoundary(Boundary):
logger.debug("Instrument = %s", self.overpass.instrument)
if self.overpass.instrument == 'viirs':
sec_scan_duration = 1.779166667
along_scan_reduce_factor = 1
elif self.overpass.instrument in ['avhrr', 'avhrr/3', 'avhrr/2']:
sec_scan_duration = 1./6.
along_scan_reduce_factor = 0.1
elif self.overpass.instrument == 'ascat':
sec_scan_duration = 3.74747474747
along_scan_reduce_factor = 1
# Overwrite the scan step
scan_step = 1
else:
# Assume AVHRR!
logmsg = ("Instrument scan duration not known. Setting it to AVHRR. Instrument: ")
logger.warning(logmsg + "%s", str(self.overpass.instrument))
sec_scan_duration = 1./6.
along_scan_reduce_factor = 0.1
# From pass length in seconds and the seconds for one scan derive the number of scans in the swath:
scans_nb = scanlength_seconds/sec_scan_duration
scans_nb = scanlength_seconds/sec_scan_duration * along_scan_reduce_factor
# Devide by the scan step to a reduced number of scans:
scans_nb = np.ceil(scans_nb/scan_step)
scans_nb = np.floor(scans_nb/scan_step)
scans_nb = int(max(scans_nb, 1))
sides_lons, sides_lats = self.get_instrument_points(self.overpass,
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2014 - 2018 PyTroll Community
# Copyright (c) 2014 - 2019 PyTroll Community
# Author(s):
# Martin Raspaud <martin.raspaud@smhi.se>
......@@ -48,6 +48,11 @@ from trollsched import (MIN_PASS, NOAA20_NAME, NUMBER_OF_FOVS)
logger = logging.getLogger(__name__)
VIIRS_PLATFORM_NAMES = ['SUOMI NPP', 'SNPP',
'NOAA-20', 'NOAA 20']
MERSI2_PLATFORM_NAMES = ['FENGYUN 3D', 'FENGYUN-3D', 'FY-3D',
'FENGYUN 3E', 'FENGYUN-3E', 'FY-3E']
class SimplePass(object):
"""A pass: satellite, risetime, falltime, (orbital)
......@@ -138,7 +143,8 @@ class Pass(SimplePass):
instrument = kwargs.get('instrument', None)
tle1 = kwargs.get('tle1', None)
tle2 = kwargs.get('tle2', None)
# logger.info("instrument: %s", str(instrument))
logger.debug("instrument: %s", str(instrument))
if isinstance(instrument, list):
logger.warning("Instrument is a list! Assume avhrr...")
instrument = 'avhrr'
......@@ -147,8 +153,10 @@ class Pass(SimplePass):
self.number_of_fovs = kwargs.get('number_of_fovs', default)
# The frequency shouldn't actualy depend on the number of FOVS along a scanline should it!?
# frequency = kwargs.get('frequency', int(self.number_of_fovs / 4))
frequency = kwargs.get('frequency', 100)
frequency = kwargs.get('frequency', 300)
self.station = None
self.max_elev = None
self.uptime = uptime or (risetime + (falltime - risetime) / 2)
self.instrument = instrument
self.frequency = frequency
......@@ -223,6 +231,7 @@ class Pass(SimplePass):
area_boundary = area_boundary.contour_poly
inter = self.boundary.contour_poly.intersection(area_boundary)
if inter is None:
return 0
return inter.area() / area_boundary.area()
......@@ -277,12 +286,38 @@ class Pass(SimplePass):
HOST = "ftp://is.sci.gsfc.nasa.gov/ancillary/ephemeris/schedule/%s/downlink/"
def get_aqua_terra_dumps_from_ftp(start_time,
def get_aqua_terra_dumps(start_time,
end_time,
satorb,
sat,
dump_url=None):
logger.info("Fetch %s dump info from internet" % sat.name)
"""
Get the Terra and Aqua overpasses taking into account the fact that when
there are global dumps there is no direct broadcast
"""
# Get the list of aqua/terra dump info:
dump_info_list = get_aqua_terra_dumpdata_from_ftp(sat, dump_url)
dumps = []
for elem in dump_info_list:
if elem['los'] >= start_time and elem['aos'] <= end_time:
uptime = elem['aos'] + (elem['los'] - elem['aos']) / 2
overpass = Pass(sat, elem['aos'], elem['los'],
orb=satorb, uptime=uptime, instrument="modis")
overpass.station = elem['station']
overpass.max_elev = elem['elev']
dumps.append(overpass)
return dumps
def get_aqua_terra_dumpdata_from_ftp(sat, dump_url):
"""
Get the information on the internet on the actual global dumps of Terra and Aqua
"""
logger.info("Fetch %s dump info from internet", str(sat.name))
if isinstance(dump_url, six.text_type):
url = urlparse(dump_url % sat.name)
else:
......@@ -347,18 +382,27 @@ def get_aqua_terra_dumps_from_ftp(start_time,
for line in fd_:
lines.append(line)
# for line in lines[7::2]:
# if line.strip() == '':
# break
# station, aos, elev, los = line.split()[:4]
# aos = datetime.strptime(aos, "%Y:%j:%H:%M:%S")
# los = datetime.strptime(los, "%Y:%j:%H:%M:%S")
# if los >= start_time and aos <= end_time:
# uptime = aos + (los - aos) / 2
# overpass = Pass(sat, aos, los, orb=satorb, uptime=uptime, instrument="modis")
# overpass.station = station
# overpass.max_elev = elev
# dumps.append(overpass)
for line in lines[7::2]:
if line.strip() == '':
break
station, aos, elev, los = line.split()[:4]
aos = datetime.strptime(aos, "%Y:%j:%H:%M:%S")
los = datetime.strptime(los, "%Y:%j:%H:%M:%S")
if los >= start_time and aos <= end_time:
uptime = aos + (los - aos) / 2
overpass = Pass(sat, aos, los, satorb, uptime, "modis")
overpass.station = station
overpass.max_elev = elev
dumps.append(overpass)
dumps.append({'station': station, 'aos': aos, 'los': los, 'elev': elev})
if f is not None:
f.quit()
return dumps
......@@ -374,9 +418,10 @@ def get_next_passes(satellites,
duration of *forward* hours, with observer at *coords* ie lon (°E), lat
(°N), altitude (km). Uses *tle_file* if provided, downloads from celestrack
otherwise.
Metop-A, Terra and Aqua need special treatment due to downlink restrictions.
"""
passes = {}
orbitals = {}
if tle_file is None and 'TLES' not in os.environ:
fp_, tle_file = mkstemp(prefix="tle", dir="/tmp")
......@@ -394,35 +439,84 @@ def get_next_passes(satellites,
sat = Satellite(sat, 0, 0)
satorb = orbital.Orbital(sat.name, tle_file=tle_file)
orbitals[sat.name] = satorb
passlist = satorb.get_next_passes(utctime, forward, *coords)
if sat.name.lower().startswith("metop") or sat.name.lower().startswith(
"noaa"):
if sat.name == "metop-a":
# Take care of metop-a
passes["metop-a"] = get_metopa_passes(sat, passlist, satorb)
elif sat.name in ["aqua", "terra"] and aqua_terra_dumps:
# Take care of aqua (dumps in svalbard and poker flat)
# Get the Terra/Aqua passes and fill the passes dict:
get_terra_aqua_passes(passes, utctime, forward, sat, passlist, satorb, aqua_terra_dumps)
else:
if sat.name.lower().startswith("metop") or sat.name.lower().startswith("noaa"):
instrument = "avhrr"
elif sat.name in ["aqua", "terra"]:
instrument = "modis"
elif sat.name.endswith("npp") or sat.name.startswith("jpss"):
elif sat.name.upper() in VIIRS_PLATFORM_NAMES:
instrument = "viirs"
elif sat.name.upper() in MERSI2_PLATFORM_NAMES:
instrument = "mersi2"
else:
instrument = "unknown"
# take care of metop-a
if sat.name == "metop-a":
metop_passes = [
passes[sat.name] = [
Pass(sat, rtime, ftime, orb=satorb, uptime=uptime, instrument=instrument)
for rtime, ftime, uptime in passlist
if ftime - rtime > timedelta(minutes=MIN_PASS)
]
return set(fctools_reduce(operator.concat, list(passes.values())))
def get_metopa_passes(sat, passlist, satorb):
"""Get the Metop-A passes, taking care that Metop-A doesn't transmit to ground
everywhere
"""
metop_passes = [
Pass(sat, rtime, ftime, orb=satorb, uptime=uptime, instrument='avhrr')
for rtime, ftime, uptime in passlist if rtime < ftime
]
passes["metop-a"] = []
passes = []
for overpass in metop_passes:
if overpass.pass_direction() == "descending":
new_rise = overpass.slsearch(60)
if new_rise is not None and new_rise < overpass.falltime:
overpass.risetime = new_rise
overpass.boundary = SwathBoundary(overpass)
# overpass has a boundary property, and it is not really needed here anyways!
# overpass.boundary = SwathBoundary(overpass)
if overpass.seconds() > MIN_PASS * 60:
passes["metop-a"].append(overpass)
# take care of aqua (dumps in svalbard and poker flat)
elif sat.name in ["aqua", "terra"] and aqua_terra_dumps:
passes.append(overpass)
return passes
def get_terra_aqua_passes(passes, utctime, forward, sat, passlist, satorb, aqua_terra_dumps):
"""Get the Terra/Aqua passes, taking care that Terra and Aqua do not have
direct broadcast when there are global dumps
passes: The dictionary of satellite passes which is being built
utctime: The start time (datetime object)
forward: The number of hours ahead for which we will get the coming passes
sat: The Satellite platform considered
passlist: List of Pass objects
satorb: Orbital instance for the actual satellite and tles considered
aqua_terra_dumps: True or False or the actual URL to get info on Terra/Aqua
dumps. If True, the default URL will be used. If False or None, no dump
info will be considered.
"""
instrument = 'modis'
wpcoords = (-75.457222, 37.938611, 0)
passlist_wp = satorb.get_next_passes(
......@@ -452,10 +546,9 @@ def get_next_passes(satellites,
for rtime, ftime, uptime in passlist if rtime < ftime
]
dumps = get_aqua_terra_dumps_from_ftp(
utctime - timedelta(minutes=30),
utctime + timedelta(hours=forward + 0.5), satorb, sat,
aqua_terra_dumps)
dumps = get_aqua_terra_dumps(utctime - timedelta(minutes=30),
utctime + timedelta(hours=forward + 0.5),
satorb, sat, aqua_terra_dumps)
# remove the known dumps
for dump in dumps:
......@@ -538,11 +631,4 @@ def get_next_passes(satellites,
if add and overpass.seconds() > MIN_PASS * 60:
passes[sat.name].append(overpass)
else:
passes[sat.name] = [
Pass(sat, rtime, ftime, orb=satorb, uptime=uptime, instrument=instrument)
for rtime, ftime, uptime in passlist
if ftime - rtime > timedelta(minutes=MIN_PASS)
]
return set(fctools_reduce(operator.concat, list(passes.values())))
return
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2013, 2014, 2015, 2016, 2017, 2018 Martin Raspaud
# Copyright (c) 2013 - 2019 PyTroll
# Author(s):
......@@ -26,22 +26,18 @@
import logging
import logging.handlers
import os
from six.moves.configparser import ConfigParser
try:
from urllib.parse import urlparse
except ImportError:
from urlparse import urlparse
from six.moves.configparser import ConfigParser
from datetime import datetime, timedelta
from pprint import pformat
import numpy as np
from pyorbital import astronomy
from pyresample import utils as resample_utils
try:
from trollsched import utils
except ImportError:
import utils
from trollsched.spherical import get_twilight_poly
from trollsched.graph import Graph
from trollsched.satpass import get_next_passes, SimplePass
......@@ -577,8 +573,11 @@ def parse_datetime(strtime):
def save_passes(allpasses, poly, output_dir):
for passage in allpasses:
passage.save_fig(poly, directory=output_dir)
"""Save overpass plots to png and store in directory *output_dir*
"""
from trollsched.drawing import save_fig
for overpass in allpasses:
save_fig(overpass, poly=poly, directory=output_dir)
def get_passes_from_xml_file(filename):
......@@ -603,6 +602,7 @@ def build_filename(pattern_name, pattern_dict, kwargs):
for v in pattern_dict.values():
if "{" + k + "}" in v:
kwargs[k] = pattern_dict[k].format(**kwargs)
return pattern_dict[pattern_name].format(**kwargs)
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2018 Adam.Dybbroe
# Copyright (c) 2018 - 2019 PyTroll
# Author(s):
# Adam.Dybbroe <a000680@c20671.ad.smhi.se>
# Adam.Dybbroe <adam.dybbroe@smhi.se>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -25,92 +25,67 @@
import unittest
import numpy as np
from datetime import datetime
from datetime import datetime, timedelta
from trollsched.satpass import Pass
from trollsched.boundary import SwathBoundary
from pyorbital.orbital import Orbital
LONS1 = np.array([-122.29913729, -126.04783309, -131.54385363, -140.34457195,
-155.78803427, 177.07901485, 143.17308804, 119.09779572,
105.69172088, 97.93616567, 93.03135572, 89.68345994,
87.26010432, 85.42516118, 83.98598585, 82.82504079,
81.86683435, 81.06077901, 80.37175346, 79.77463329,
79.25097987, 78.786959, 78.37198927, 77.99783892,
77.65800714, 77.34729064, 77.06147401, 76.79710452,
76.55132567, 76.32175241, 76.10637628, 75.90349247,
75.71164307, 75.52957243, 75.35619181, 75.19055092,
75.03181505, 74.87924636, 74.73218847, 74.59005373,
74.45231256, 74.31848442, 74.18813012, 74.0608452,
73.93625404, 73.81400477, 73.69376448, 73.57521487,
73.45804805, 73.34196235, 73.22665809, 73.11183296,
72.99717693, 72.88236627, 72.76705639, 72.65087264,
72.53339842, 72.41415887, 72.29259784, 72.16804392,
72.03965796, 71.90634749, 71.76661774, 71.61828892,
71.45957469, 66.02111672, 60.62910317, 55.36663834,
50.30484964, 45.49802549, 40.98192779, 36.77486609,
32.88055429, 29.29169986, 25.99352548, 22.96676778,
20.18998791, 17.64121314, 15.29901722, 13.14317182,
11.1549917, 9.3174736, 7.61530331, 6.0347843,
4.5637236, 3.19129834, 1.90791769, -0.27010734,
-1.78807143, -3.06483263, -4.15881214, -5.116189,
-5.96754616, -6.73429808, -7.43207874, -8.07268005,
-8.66523239, -9.21696007, -9.73368473, -10.22017188,
-10.68037653, -11.11762133, -11.53472862, -11.93412013,
-12.31789334, -12.68788113, -13.04569866, -13.392781,
-13.73041348, -14.05975651, -14.38186617, -14.69771139,
-15.0081885, -15.31413371, -15.61633396, -15.91553641,
-16.21245702, -16.50778829, -16.80220647, -17.0963784,
-17.39096805, -17.68664309, -17.98408147, -18.28397825,
-18.58705276, -18.89405641, -19.2057812, -19.5230692,
-19.84682337, -20.17801994, -20.51772283, -20.86710061,
-21.22744677, -21.60020406, -21.98699405, -22.38965364,
-22.81028023, -23.25128869, -23.71548384, -24.20615392,
-24.7271931, -25.28326445, -25.88002092, -26.52441138,
-27.2251146, -27.99317242, -28.84294497, -29.79361073,
-30.87164244, -32.11515837, -33.58222589, -35.36860848,
-35.21433484, -35.1791126, -35.18076657, -35.22429227,
-35.31584841, -35.46309023, -35.67562508, -35.96564469,
-36.34881853, -36.84558066, -37.48302415, -38.29775696,
-39.3403228, -40.68224432, -42.42759794, -44.73265038,
-47.84014874, -52.14015034, -58.27495326, -67.28863935,
-80.65010901, -99.30453147], dtype='float64')
LATS1 = np.array([84.60636068, 85.92648911, 86.98555849, 87.84164277, 88.49911968,
88.88834005, 88.90233394, 88.62448747, 88.23555366, 87.82310862,
87.41630911, 87.02428912, 86.64939216, 86.29150279, 85.94959841,
85.6223543, 85.30839168, 85.00638004, 84.71507626, 84.43333547,
84.16010932, 83.89443866, 83.63544439, 83.38231774, 83.134311,
82.89072884, 82.65092035, 82.4142718, 82.18020003, 81.94814634,
81.71757085, 81.4879472, 81.25875744, 81.02948708, 80.79962022,
80.5686345, 80.33599603, 80.10115389, 79.86353437, 79.62253449,
79.37751496, 79.12779203, 78.87262831, 78.61122202, 78.3426943,
78.06607423, 77.78028072, 77.48410052, 77.1761612, 76.85489755,
76.51850934, 76.16490749, 75.7916446, 75.3958239, 74.97397798,
74.52190409, 74.03443589, 73.50511898, 72.92573674, 72.28559309,
71.57038281, 70.76032058, 69.82683886, 68.72625465, 67.40109717,
67.39527506, 67.1998889, 66.81969821, 66.26351933, 65.54326755,
64.67282502, 63.66694946, 62.54037135, 61.3071424, 59.98023066,
58.57131903, 57.09075181, 55.54757738, 53.94964584, 52.30373254,
50.6156685, 48.89046658, 47.13243744, 45.34529268, 43.53223486,
41.69603483, 39.83909758, 36.33799057, 36.81661145, 37.20036236,
37.5157317, 37.78169599, 38.01045368, 38.21030843, 38.38716181,
38.54535234, 38.68815761, 38.81811012, 38.93720418, 39.04703598,
39.14890123, 39.24386487, 39.33281184, 39.41648483, 39.49551278,
39.57043268, 39.64170648, 39.70973443, 39.77486557, 39.83740624,
39.89762686, 39.95576757, 40.01204278, 40.06664499, 40.11974793,
40.17150924, 40.22207272, 40.27157024, 40.32012336, 40.36784474,
40.41483935, 40.46120554, 40.5070359, 40.55241811, 40.59743562,
40.64216823, 40.68669262, 40.73108281, 40.77541046, 40.81974518,
40.86415471, 40.90870493, 40.95345981, 40.99848114, 41.043828,
41.08955592, 41.13571558, 41.18235086, 41.22949601, 41.27717143,
41.32537756, 41.37408581, 41.42322508, 41.47266125, 41.5221656,
41.57136466, 41.61965857, 41.66608254, 41.70906088, 41.74594256,
41.77205078, 41.7785075, 45.44971128, 47.49263795, 49.53356846,
51.57221573, 53.60824704, 55.64126787, 57.67079975, 59.69624952,
61.71686578, 63.73167578, 65.73939198, 67.73826987, 69.72588497,
71.69877148, 73.65181389, 75.57717873, 77.46235016, 79.28634129,
81.01208492, 82.57105105, 83.83562001, 84.59522958], dtype='float64')
LONS1 = np.array([-122.29913729160562, -131.54385362589042, -155.788034272281,
143.1730880418349, 105.69172088208997, 93.03135571771092,
87.26010432019743, 83.98598584966442, 81.86683434871546,
80.37175346216411, 79.2509798668123, 78.37198926578984,
77.65800714027662, 77.06147400915819, 76.55132566889495,
76.10637628220547, 75.71164306799828, 75.35619180525052,
75.03181505238287, 74.73218847041143, 74.45231256197947,
74.18813012461848, 73.9362540393912, 73.69376447765231,
73.45804804675883, 73.22665809422263, 72.99717692793544,
72.76705638792168, 72.53339841609603, 72.2925978414254,
72.03965795937306, 71.76661774368146, 71.45957469190316,
57.97687872167697, 45.49802548616658, 34.788857347919546,
25.993525469714424, 18.88846123000295, 13.14317179269443,
8.450362684274728, -0.27010733525252295, -3.0648326302431794,
-5.116189000358824, -6.73429807721795, -8.072680053386163,
-9.21696007364773, -10.220171884036919, -11.11762132513045,
-11.934120125548072, -12.687881125682765, -13.392781001351315,
-14.059756511026736, -14.69771138916782, -15.314133712696703,
-15.915536409615735, -16.507788289068856, -17.09637839792269,
-17.686643087306685, -18.283978247944123, -18.894056410060063,
-19.523069195727878, -20.17801994245519, -20.867100607022966,
-21.600204055760642, -22.389653641849733, -23.251288693929943,
-24.206153922914886, -25.283264445138713, -26.524411381004743,
-27.993172418988525, -29.79361072725673, -32.11515837055801,
-35.36860848223405, -35.38196057933595, -35.96564490844792,
-37.14469461070555, -39.34032289002443, -43.49756191648018,
-52.140150361811244, -73.32968630186114], dtype='float64')
LATS1 = np.array([84.60636067724808, 86.98555849233523, 88.49911967556697,
88.90233393880413, 88.23555365613707, 87.41630911481282,
86.64939216187459, 85.94959841469182, 85.30839167814023,
84.71507625588431, 84.16010931725756, 83.63544438659248,
83.13431099825148, 82.65092034888734, 82.18020003036649,
81.71757084925224, 81.25875743723827, 80.79962022032255,
80.33599602524967, 79.86353436733512, 79.37751495806062,
78.87262831355378, 78.3426942980262, 77.78028071690198,
77.17616119674511, 76.51850934329316, 75.79164459606967,
74.97397797613992, 74.03443588562436, 72.92573674313518,
71.57038280824118, 69.82683886377178, 67.40109717220513,
67.03242839212335, 65.54326755696877, 63.11784822611803,
59.98023069591168, 56.32647323215378, 52.30373268534935,
48.01531077177335, 36.33799056582854, 37.200362356448125,
37.78169598891329, 38.210308430109684, 38.54535234179983,
38.8181101172057, 39.0470359762339, 39.24386487280032,
39.41648482997921, 39.57043267820405, 39.70973443234515,
39.83740623634436, 39.955767569171485, 40.06664498984812,
40.17150923539549, 40.271570238680745, 40.36784473887322,
40.46120553672548, 40.55241811035527, 40.64216822927882,
40.7310828091462, 40.819745180454284, 40.90870492549053,
40.99848114410508, 41.08955592221846, 41.18235086149538,
41.27717142920562, 41.37408580927609, 41.472661254399455,
41.57136466452366, 41.66608254408796, 41.745942562974314,
41.77850750277849, 54.62516158367828, 59.69624962433962,
64.7365168572082, 69.72588498397877, 74.61859631181376,
79.2863412851444, 83.25136141880888], dtype='float64')
LONS2 = np.array([-174.41109502, 167.84584132, 148.24213696, 130.10334782,
115.7074828, 105.07369809, 97.28481583, 91.4618503,
......@@ -120,15 +95,15 @@ LONS2 = np.array([-174.41109502, 167.84584132, 148.24213696, 130.10334782,
65.79407472, 64.86682945, 63.97016605, 63.09478077,
62.23190558, 61.37287373, 60.50863405, 59.62912286,
58.72232744, 57.77268809, 56.75796498, 55.6419694,
54.36007027, 49.02060788, 41.41762911, 41.15660793,
40.9331126, 40.73252665, 40.54677784, 40.37092304,
40.20150965, 40.0358693, 39.87175642, 39.70713409,
39.54002703, 39.36840323, 39.1900621, 39.00251256,
38.80282499, 38.58743647, 38.35188019, 38.09039231,
37.79531831, 37.45618154, 37.05815986, 36.57947382,
35.98665163, 35.22533847, 34.20085643, 32.73220377,
30.42514135, 26.23397747, 16.29417395, -23.91719576,
-102.71481425, -122.5294795, -129.09284487, -157.23082856], dtype='float64')
54.36007027, 41.41762911, 41.15660793, 40.9331126,
40.73252665, 40.54677784, 40.37092304, 40.20150965,
40.0358693, 39.87175642, 39.70713409, 39.54002703,
39.36840323, 39.1900621, 39.00251256, 38.80282499,
38.58743647, 38.35188019, 38.09039231, 37.79531831,
37.45618154, 37.05815986, 36.57947382, 35.98665163,
35.22533847, 34.20085643, 32.73220377, 30.42514135,
26.23397747, 16.29417395, -23.91719576, -102.71481425,
-122.5294795, -129.09284487], dtype='float64')
LATS2 = np.array([83.23214786, 84.90973645, 85.62529048, 85.74243351, 85.52147568,
85.13874302, 84.69067959, 84.22338069, 83.75720094, 83.30023412,
......@@ -136,36 +111,22 @@ LATS2 = np.array([83.23214786, 84.90973645, 85.62529048, 85.74243351, 85.5214756
80.75376801, 80.34133891, 79.92463458, 79.50028749, 79.0645828,
78.61332046, 78.14162813, 77.64370408, 77.11245516, 76.5389713,
75.91173559, 75.21538754, 74.42869094, 73.52099029, 72.44554294,
71.12561977, 69.42093758, 67.03973793, 67.32482671, 67.40770791,
69.8341456, 71.57844446, 72.93459921, 74.04414258, 74.98457279,
75.80317362, 76.53102217, 77.1897121, 77.79492994, 78.3585095,
78.88968633, 79.39590402, 79.88335693, 80.35737249, 80.8226939,
81.28370137, 81.74459732, 82.20957417, 82.68298027, 83.16949849,
83.67435372, 84.20356848, 84.76429067, 85.36521771, 86.01711637,
86.73327122, 87.5286869, 88.40887156, 89.21959299, 88.71884272,
87.09172665, 84.6670132, 84.33222435], dtype='float64')
LONS3 = np.array([-8.90844155, -6.41788507, 15.9722481, 25.41135812, 33.82664554,
48.40057578, 49.68649967, 49.67357678, 49.660659, 49.64774633,
49.63483878, 49.62193632, 49.60903897, 49.59614672, 49.58325957,
49.57037752, 49.55750056, 49.54462869, 49.53176192, 49.51890023,
49.50604363, 49.49319211, 49.48034567, 45.3479991, 44.06777983,
30.05979749, 22.33029612, 13.8829146, -5.77610172, -7.97353711,
-8.8574793, -8.86063533, -8.86379522, -8.86695898, -8.8701266,
-8.8732981, -8.87647348, -8.87965274, -8.88283588, -8.88602292,
-8.88921386, -8.89240869, -8.89560744, -8.89881009, -8.90201665,
-8.90522714], dtype='float64')
LATS3 = np.array([66.93178962, 67.06891155, 66.53360116, 65.27837503, 63.4969562,
58.28365842, 57.64571471, 57.63885271, 57.63198927, 57.62512438,
57.61825804, 57.61139026, 57.60452105, 57.59765039, 57.59077829,
57.58390475, 57.57702977, 57.57015336, 57.56327551, 57.55639622,
57.5495155, 57.54263335, 57.53574976, 55.08857632, 55.67467008,
60.40416556, 61.99561206, 63.11651715, 63.66434851, 63.55726406,
66.78221588, 66.79156549, 66.80091493, 66.8102642, 66.81961331,
66.82896226, 66.83831103, 66.84765964, 66.85700809, 66.86635637,
66.87570448, 66.88505242, 66.89440019, 66.9037478, 66.91309524,
66.92244251], dtype='float64')
71.12561977, 69.42093758, 67.03973793, 67.40770791, 69.8341456,
71.57844446, 72.93459921, 74.04414258, 74.98457279, 75.80317362,
76.53102217, 77.1897121, 77.79492994, 78.3585095, 78.88968633,
79.39590402, 79.88335693, 80.35737249, 80.8226939, 81.28370137,
81.74459732, 82.20957417, 82.68298027, 83.16949849, 83.67435372,
84.20356848, 84.76429067, 85.36521771, 86.01711637, 86.73327122,
87.5286869, 88.40887156, 89.21959299, 88.71884272, 87.09172665,
84.6670132], dtype='float64')
LONS3 = np.array([-8.66259458, -6.20984986, 15.99813586, 25.41134052, 33.80598414,
48.28641356, 49.55596283, 45.21769275, 43.95449327, 30.04053601,
22.33028017, 13.90584249, -5.59290326, -7.75625031], dtype='float64')
LATS3 = np.array([66.94713585, 67.07854554, 66.53108388, 65.27837805, 63.50223596,
58.33858588, 57.71210872, 55.14964148, 55.72506407, 60.40889798,
61.99561474, 63.11425455, 63.67173255, 63.56939058], dtype='float64')
def assertNumpyArraysEqual(self, other):
......@@ -246,6 +207,14 @@ class TestSwathBoundary(unittest.TestCase):
assertNumpyArraysEqual(cont[0], LONS3)
assertNumpyArraysEqual(cont[1], LATS3)
overp = Pass('NOAA-19', tstart, tend, orb=self.n19orb, instrument='avhrr/3')
overp_boundary = SwathBoundary(overp, frequency=500)
cont = overp_boundary.contour()
assertNumpyArraysEqual(cont[0], LONS3)
assertNumpyArraysEqual(cont[1], LATS3)
def test_swath_coverage(self):
# NOAA-19 AVHRR:
......@@ -268,22 +237,47 @@ class TestSwathBoundary(unittest.TestCase):
overp = Pass('NOAA-19', tstart, tend, orb=self.n19orb, instrument='avhrr')
cov = overp.area_coverage(self.euron1)
self.assertAlmostEqual(cov, 0.103960, 5)
self.assertAlmostEqual(cov, 0.103526, 5)
overp = Pass('NOAA-19', tstart, tend, orb=self.n19orb, instrument='avhrr', frequency=100)
cov = overp.area_coverage(self.euron1)
self.assertAlmostEqual(cov, 0.103960, 5)
self.assertAlmostEqual(cov, 0.103526, 5)
overp = Pass('NOAA-19', tstart, tend, orb=self.n19orb, instrument='avhrr', frequency=133)
overp = Pass('NOAA-19', tstart, tend, orb=self.n19orb, instrument='avhrr/3', frequency=133)
cov = overp.area_coverage(self.euron1)
self.assertAlmostEqual(cov, 0.103960, 5)
self.assertAlmostEqual(cov, 0.103526, 5)
overp = Pass('NOAA-19', tstart, tend, orb=self.n19orb, instrument='avhrr', frequency=300)
cov = overp.area_coverage(self.euron1)
self.assertAlmostEqual(cov, 0.103960, 5)
self.assertAlmostEqual(cov, 0.103526, 5)
# ASCAT and AVHRR on Metop-B:
tstart = datetime.strptime("2019-01-02T10:19:39", "%Y-%m-%dT%H:%M:%S")
tend = tstart + timedelta(seconds=180)
tle1 = '1 38771U 12049A 19002.35527803 .00000000 00000+0 21253-4 0 00017'
tle2 = '2 38771 98.7284 63.8171 0002025 96.0390 346.4075 14.21477776326431'
mypass = Pass('Metop-B', tstart, tend, instrument='ascat', tle1=tle1, tle2=tle2)
cov = mypass.area_coverage(self.euron1)
self.assertAlmostEqual(cov, 0.322812, 5)
mypass = Pass('Metop-B', tstart, tend, instrument='avhrr', tle1=tle1, tle2=tle2)
cov = mypass.area_coverage(self.euron1)
self.assertAlmostEqual(cov, 0.357324, 5)
tstart = datetime.strptime("2019-01-05T01:01:45", "%Y-%m-%dT%H:%M:%S")
tend = tstart + timedelta(seconds=60*15.5)
tle1 = '1 43010U 17072A 18363.54078832 -.00000045 00000-0 -79715-6 0 9999'
tle2 = '2 43010 98.6971 300.6571 0001567 143.5989 216.5282 14.19710974 58158'
mypass = Pass('FENGYUN 3D', tstart, tend, instrument='mersi2', tle1=tle1, tle2=tle2)
cov = mypass.area_coverage(self.euron1)
self.assertAlmostEqual(cov, 0.786836, 5)
def tearDown(self):
"""Clean up"""
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2014, 2018 Martin Raspaud
# Copyright (c) 2014 - 2019 PyTroll
# Author(s):
# Martin Raspaud <martin.raspaud@smhi.se>
# Adam Dybbroe <adam.dybbroe@smhi.se>
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
......@@ -23,12 +24,27 @@
"""Test the schedule module.
"""
import unittest
import numpy as np
from datetime import datetime, timedelta
from trollsched.schedule import fermia, fermib, conflicting_passes
from trollsched.schedule import parse_datetime, build_filename
from pyresample.boundary import AreaBoundary
from trollsched.satpass import get_next_passes
from trollsched.satpass import get_aqua_terra_dumps
from trollsched.satpass import get_metopa_passes
import sys
if sys.version_info < (2, 7):
import unittest2 as unittest
else:
import unittest
try:
from unittest.mock import patch
except ImportError:
from mock import patch
# class TestPass(unittest.TestCase):
......@@ -138,17 +154,264 @@ class TestUtils(unittest.TestCase):
self.assertEquals(fermia(0.25), 0.875)
self.assertEquals(fermib(0.25), 0.5)
def test_parse_datetime(self):
dtobj = parse_datetime('20190104110059')
self.assertEqual(dtobj, datetime(2019, 1, 4, 11, 0, 59))
def test_build_filename(self):
pattern_name = "dir_output"
pattern_dict = {'file_xml': '{dir_output}/{date}-{time}-aquisition-schedule-{mode}-{station}.xml', 'file_sci': '{dir_output}/scisys-schedule-{station}.txt',
'dir_plots': '{dir_output}/plots.{station}', 'dir_output': '/tmp', 'file_graph': '{dir_output}/graph.{station}'}
kwargs = {'date': '20190104', 'output_dir': '.', 'dir_output': '/tmp', 'time': '122023'}
res = build_filename(pattern_name, pattern_dict, kwargs)
self.assertEqual(res, '/tmp')
pattern_name = "file_xml"
kwargs = {'station': 'nrk', 'mode': 'request', 'time': '125334',
'date': '20190104', 'dir_output': '/tmp', 'output_dir': '.'}
res = build_filename(pattern_name, pattern_dict, kwargs)
self.assertEqual(res, '/tmp/20190104-125334-aquisition-schedule-request-nrk.xml')
class TestAll(unittest.TestCase):
def test_gen(self):
utctime = datetime(2014, 1, 18, 14, 20)
satellites = ["noaa 19", "noaa 18", "noaa 16", "noaa 15",
"metop-a", "metop-b",
"terra", "aqua",
"suomi npp"]
tle_file = "./tle_20140120.txt"
#allpasses = get_next_passes(satellites, utctime, 2, tle_file)
def setUp(self):
"""Set up"""
from pyorbital import orbital
from trollsched.schedule import Satellite
self.utctime = datetime(2018, 11, 28, 10, 0)
self.satellites = ["noaa-20", ]
self.tles = {'noaa-20': {}}
self.tles['noaa-20']['line1'] = "1 43013U 17073A 18331.00000000 .00000048 00000-0 22749-4 0 3056"
self.tles['noaa-20']['line2'] = "2 43013 098.7413 267.0121 0001419 108.5818 058.1314 14.19552981053016"
self.aquas = ["aqua", ]
self.terras = ["terra", ]
self.terra = Satellite('terra', 0, 0)
self.metopa = Satellite('metop-a', 0, 0)
self.tles['aqua'] = {}
self.tles['aqua']['line1'] = "1 27424U 02022A 18332.21220389 .00000093 00000-0 30754-4 0 9994"
self.tles['aqua']['line2'] = "2 27424 98.2121 270.9368 0001045 343.9225 155.8703 14.57111538881313"
self.tles['terra'] = {}
self.tles['terra']['line1'] = "1 25994U 99068A 18338.20920286 .00000076 00000-0 26867-4 0 9999"
self.tles['terra']['line2'] = "2 25994 98.2142 50.5750 0000577 102.5211 257.6060 14.57132862 8586"
self.tles['metop-a'] = {}
self.tles['metop-a']['line1'] = "1 29499U 06044A 18338.30873671 .00000000 00000+0 31223-4 0 00013"
self.tles['metop-a']['line2'] = "2 29499 98.6045 31.7725 0001942 91.8780 346.4884 14.21536046629175"
self.orb = orbital.Orbital('NOAA 20',
line1=self.tles['noaa-20']['line1'],
line2=self.tles['noaa-20']['line2'])
self.aqua_orb = orbital.Orbital('AQUA',
line1=self.tles['aqua']['line1'],
line2=self.tles['aqua']['line2'])
self.terra_orb = orbital.Orbital('TERRA',
line1=self.tles['terra']['line1'],
line2=self.tles['terra']['line2'])
self.metopa_orb = orbital.Orbital('Metop-A',
line1=self.tles['metop-a']['line1'],
line2=self.tles['metop-a']['line2'])
# These values were used to generate the get_next_passes list mock:
# utctime = datetime(2018, 12, 4, 9, 0)
# forward = 6
# coords = (16, 58, 0)
self.metopa_passlist = [(datetime(2018, 12, 4, 9, 10, 4, 574801),
datetime(2018, 12, 4, 9, 25, 29, 157194),
datetime(2018, 12, 4, 9, 17, 48, 530484)),
(datetime(2018, 12, 4, 10, 50, 23, 899232),
datetime(2018, 12, 4, 11, 4, 2, 335184),
datetime(2018, 12, 4, 10, 57, 13, 691637)),
(datetime(2018, 12, 4, 12, 30, 24, 97160),
datetime(2018, 12, 4, 12, 40, 42, 403698),
datetime(2018, 12, 4, 12, 35, 33, 317647)),
(datetime(2018, 12, 4, 14, 9, 1, 937869),
datetime(2018, 12, 4, 14, 17, 20, 556654),
datetime(2018, 12, 4, 14, 13, 11, 247497))]
self.dumpdata = [
{'los': datetime(2018, 11, 28, 10, 0, 30), 'station': 'USAK05',
'aos': datetime(2018, 11, 28, 9, 50, 24), 'elev': '11.188'},
{'los': datetime(2018, 11, 28, 11, 39, 47), 'station': 'AS2',
'aos': datetime(2018, 11, 28, 11, 28, 51), 'elev': '39.235'},
{'los': datetime(2018, 11, 28, 13, 19, 8), 'station': 'USAK05',
'aos': datetime(2018, 11, 28, 13, 6, 36), 'elev': '58.249'},
{'los': datetime(2018, 11, 28, 14, 54, 25), 'station': 'AS2',
'aos': datetime(2018, 11, 28, 14, 44, 37), 'elev': '22.403'},
{'los': datetime(2018, 11, 28, 16, 27, 22), 'station': 'SG1',
'aos': datetime(2018, 11, 28, 16, 16, 58), 'elev': '9.521'}
]
self.dumpdata_terra = [{'los': datetime(2018, 11, 20, 23, 24, 41), 'station': 'SG2',
'aos': datetime(2018, 11, 20, 23, 12, 32), 'elev': '17.4526'},
{'los': datetime(2018, 11, 22, 23, 19, 21), 'station': 'AS3',
'aos': datetime(2018, 11, 22, 23, 8, 55), 'elev': '28.9558'},
{'los': datetime(2018, 11, 22, 23, 19, 21), 'station': 'AS3',
'aos': datetime(2018, 11, 22, 23, 8, 55), 'elev': '28.9558'},
{'los': datetime(2018, 11, 26, 22, 47, 34), 'station': 'SG1',
'aos': datetime(2018, 11, 26, 22, 34, 58), 'elev': '21.5694'},
{'los': datetime(2018, 11, 26, 22, 47, 34), 'station': 'SG1',
'aos': datetime(2018, 11, 26, 22, 34, 58), 'elev': '21.5694'},
{'los': datetime(2018, 11, 26, 22, 47, 34), 'station': 'SG1',
'aos': datetime(2018, 11, 26, 22, 34, 58), 'elev': '21.5694'},
{'los': datetime(2018, 11, 27, 23, 30, 44), 'station': 'SG2',
'aos': datetime(2018, 11, 27, 23, 18, 39), 'elev': '16.8795'},
{'los': datetime(2018, 11, 27, 23, 30, 44), 'station': 'SG2',
'aos': datetime(2018, 11, 27, 23, 18, 39), 'elev': '16.8795'},
{'los': datetime(2018, 11, 28, 22, 43, 53), 'station': 'USAK05',
'aos': datetime(2018, 11, 28, 22, 31, 57), 'elev': '40.9264'},
{'los': datetime(2018, 11, 28, 22, 43, 53), 'station': 'USAK05',
'aos': datetime(2018, 11, 28, 22, 31, 57), 'elev': '40.9264'},
{'los': datetime(2018, 11, 29, 23, 25, 11), 'station': 'USAK05',
'aos': datetime(2018, 11, 29, 23, 14, 47), 'elev': '26.9937'},
{'los': datetime(2018, 11, 29, 23, 25, 11), 'station': 'USAK05',
'aos': datetime(2018, 11, 29, 23, 14, 47), 'elev': '26.9937'},
{'los': datetime(2018, 11, 30, 22, 31, 3), 'station': 'AS2',
'aos': datetime(2018, 11, 30, 22, 19, 48), 'elev': '47.8599'},
{'los': datetime(2018, 12, 1, 1, 29, 2), 'station': 'WG1',
'aos': datetime(2018, 12, 1, 1, 21, 11), 'elev': '8.0543'},
{'los': datetime(2018, 11, 30, 22, 31, 3), 'station': 'AS2',
'aos': datetime(2018, 11, 30, 22, 19, 48), 'elev': '47.8599'},
{'los': datetime(2018, 12, 1, 1, 29, 2), 'station': 'WG1',
'aos': datetime(2018, 12, 1, 1, 21, 11), 'elev': '8.0543'},
{'los': datetime(2018, 12, 3, 1, 28, 14), 'station': 'SG2',
'aos': datetime(2018, 12, 3, 1, 17, 53), 'elev': '9.2428'},
{'los': datetime(2018, 12, 3, 22, 53, 35), 'station': 'SG1',
'aos': datetime(2018, 12, 3, 22, 41, 5), 'elev': '20.8371'},
{'los': datetime(2018, 12, 3, 22, 53, 35), 'station': 'SG1',
'aos': datetime(2018, 12, 3, 22, 41, 5), 'elev': '20.8371'},
{'los': datetime(2018, 12, 4, 23, 43, 5), 'station': 'AS2',
'aos': datetime(2018, 12, 4, 23, 33, 8), 'elev': '23.546'}]
@patch('os.path.exists')
def test_get_next_passes_viirs(self, exists):
exists.return_code = True
# mymock:
with patch('pyorbital.orbital.Orbital') as mymock:
instance = mymock.return_value
instance.get_next_passes = self.orb.get_next_passes
allpasses = get_next_passes(self.satellites, self.utctime,
4, (16, 58, 0), tle_file='nonexisting')
self.assertEqual(len(allpasses), 2)
n20pass1 = allpasses.pop()
rt1 = datetime(2018, 11, 28, 10, 53, 42, 79483)
ft1 = datetime(2018, 11, 28, 11, 9, 6, 916787)
rt2 = datetime(2018, 11, 28, 12, 34, 44, 667963)
ft2 = datetime(2018, 11, 28, 12, 49, 25, 134067)
dt_ = n20pass1.risetime - rt1
self.assertAlmostEqual(dt_.seconds, 0)
dt_ = n20pass1.falltime - ft1
self.assertAlmostEqual(dt_.seconds, 0)
n20pass2 = allpasses.pop()
dt_ = n20pass2.risetime - rt2
self.assertAlmostEqual(dt_.seconds, 0)
dt_ = n20pass2.falltime - ft2
self.assertAlmostEqual(dt_.seconds, 0)
@patch('os.path.exists')
@patch('trollsched.satpass.get_aqua_terra_dumpdata_from_ftp')
def test_get_next_passes_with_aquadumps(self, dumps_from_ftp, exists):
dumps_from_ftp.return_value = self.dumpdata
exists.return_code = True
# mymock:
with patch('pyorbital.orbital.Orbital') as mymock:
instance = mymock.return_value
instance.get_next_passes = self.aqua_orb.get_next_passes
allpasses = get_next_passes(self.aquas, self.utctime,
6, (16, 58, 0), tle_file='nonexisting',
aqua_terra_dumps=True)
self.assertEqual(len(allpasses), 3)
rt1 = datetime(2018, 11, 28, 11, 12, 8, 728455)
ft1 = datetime(2018, 11, 28, 11, 26, 8, 250021)
rt2 = datetime(2018, 11, 28, 12, 50, 46, 574975)
ft2 = datetime(2018, 11, 28, 13, 3, 53, 262440)
rt3 = datetime(2018, 11, 28, 14, 33, 33, 973194)
ft3 = datetime(2018, 11, 28, 14, 40, 10, 761405)
for mypass in allpasses:
dtmin = timedelta(seconds=10000000)
for risetime in [rt1, rt2, rt3]:
dt_ = abs(mypass.risetime - risetime)
if dt_ < dtmin:
dtmin = dt_
self.assertAlmostEqual(dtmin.seconds, 0)
dtmin = timedelta(seconds=10000000)
for falltime in [ft1, ft2, ft3]:
dt_ = abs(mypass.falltime - falltime)
if dt_ < dtmin:
dtmin = dt_
self.assertAlmostEqual(dtmin.seconds, 0)
@patch('trollsched.satpass.get_aqua_terra_dumpdata_from_ftp')
def test_get_aqua_terra_dumps(self, dumps_from_ftp):
dumps_from_ftp.return_value = self.dumpdata_terra
# mymock:
with patch('pyorbital.orbital.Orbital') as mymock:
instance = mymock.return_value
instance.get_next_passes = self.terra_orb.get_next_passes
dumps = get_aqua_terra_dumps(datetime(2018, 12, 3, 0, 0),
datetime(2018, 12, 10, 0, 0),
self.terra_orb,
self.terra)
self.assertEqual(len(dumps), 4)
self.assertEqual(dumps[0].station, 'SG2')
self.assertEqual(dumps[0].max_elev, '9.2428')
self.assertEqual(dumps[0].pass_direction(), 'ascending')
self.assertEqual((dumps[0].risetime - datetime(2018, 12, 3, 1, 17, 53)).seconds, 0)
self.assertEqual((dumps[0].falltime - datetime(2018, 12, 3, 1, 28, 14)).seconds, 0)
self.assertEqual(dumps[3].station, 'AS2')
self.assertEqual(dumps[3].max_elev, '23.546')
self.assertEqual(dumps[3].pass_direction(), 'descending')
self.assertEqual((dumps[3].risetime - datetime(2018, 12, 4, 23, 33, 8)).seconds, 0)
self.assertEqual((dumps[3].falltime - datetime(2018, 12, 4, 23, 43, 5)).seconds, 0)
@patch('os.path.exists')
def test_get_metopa_passes(self, exists):
exists.return_code = True
# mymock:
with patch('pyorbital.orbital.Orbital') as mymock:
instance = mymock.return_value
instance.get_next_passes = self.metopa_orb.get_next_passes
metopa_passes = get_metopa_passes(self.metopa, self.metopa_passlist, self.metopa_orb)
self.assertEqual(len(metopa_passes), 2)
self.assertEqual(metopa_passes[0].pass_direction(), 'descending')
self.assertEqual(metopa_passes[0].seconds(), 462.466119)
self.assertEqual((metopa_passes[0].uptime - datetime(2018, 12, 4, 9, 17, 48, 530484)).seconds, 0)
self.assertEqual((metopa_passes[0].risetime - datetime(2018, 12, 4, 9, 17, 46, 691075)).seconds, 0)
def tearDown(self):
"""Clean up"""
pass
def suite():
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Copyright (c) 2014, 2018 Martin Raspaud
# This file helps to compute a version number in source trees obtained from
# git-archive tarball (such as those provided by githubs download-from-tag
# feature). Distribution tarballs (built by setup.py sdist) and build
# directories (produced by setup.py build) will contain a much shorter file
# that just contains the computed version number.
# Author(s):
# This file is released into the public domain. Generated by
# versioneer-0.18 (https://github.com/warner/python-versioneer)
# Martin Raspaud <martin.raspaud@smhi.se>
"""Git implementation of _version.py."""
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
import errno
import os
import re
import subprocess
import sys
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
def get_keywords():
"""Get the keywords needed to look up the version information."""
# these strings will be replaced by git during git-archive.
# setup.py/versioneer.py will grep for the variable names, so they must
# each be defined on a line of their own. _version.py will just call
# get_keywords().
git_refnames = " (HEAD -> master, tag: v0.5.1)"
git_full = "d91b43d7047454197ac960118dafd7294349ae6f"
git_date = "2019-01-08 21:15:09 +0100"
keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
return keywords
"""Version file.
class VersioneerConfig:
"""Container for Versioneer configuration parameters."""
def get_config():
"""Create, populate and return the VersioneerConfig() object."""
# these strings are filled in when 'setup.py versioneer' creates
# _version.py
cfg = VersioneerConfig()
cfg.VCS = "git"
cfg.style = "pep440"
cfg.tag_prefix = "v"
cfg.parentdir_prefix = ""
cfg.versionfile_source = "trollsched/version.py"
cfg.verbose = False
return cfg
class NotThisMethod(Exception):
"""Exception raised if a method is not valid for the current scenario."""
LONG_VERSION_PY = {}
HANDLERS = {}
def register_vcs_handler(vcs, method): # decorator
"""Decorator to mark a method as the handler for a particular VCS."""
def decorate(f):
"""Store f in HANDLERS[vcs][method]."""
if vcs not in HANDLERS:
HANDLERS[vcs] = {}
HANDLERS[vcs][method] = f
return f
return decorate
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
env=None):
"""Call the given command(s)."""
assert isinstance(commands, list)
p = None
for c in commands:
try:
dispcmd = str([c] + args)
# remember shell=False, so use git.cmd on windows, not just git
p = subprocess.Popen([c] + args, cwd=cwd, env=env,
stdout=subprocess.PIPE,
stderr=(subprocess.PIPE if hide_stderr
else None))
break
except EnvironmentError:
e = sys.exc_info()[1]
if e.errno == errno.ENOENT:
continue
if verbose:
print("unable to run %s" % dispcmd)
print(e)
return None, None
else:
if verbose:
print("unable to find command, tried %s" % (commands,))
return None, None
stdout = p.communicate()[0].strip()
if sys.version_info[0] >= 3:
stdout = stdout.decode()
if p.returncode != 0:
if verbose:
print("unable to run %s (error)" % dispcmd)
print("stdout was %s" % stdout)
return None, p.returncode
return stdout, p.returncode
def versions_from_parentdir(parentdir_prefix, root, verbose):
"""Try to determine the version from the parent directory name.
Source tarballs conventionally unpack into a directory that includes both
the project name and a version string. We will also support searching up
two directory levels for an appropriately named parent directory
"""
rootdirs = []
for i in range(3):
dirname = os.path.basename(root)
if dirname.startswith(parentdir_prefix):
return {"version": dirname[len(parentdir_prefix):],
"full-revisionid": None,
"dirty": False, "error": None, "date": None}
else:
rootdirs.append(root)
root = os.path.dirname(root) # up a level
if verbose:
print("Tried directories %s but none started with prefix %s" %
(str(rootdirs), parentdir_prefix))
raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
@register_vcs_handler("git", "get_keywords")
def git_get_keywords(versionfile_abs):
"""Extract version information from the given file."""
# the code embedded in _version.py can just fetch the value of these
# keywords. When used from setup.py, we don't want to import _version.py,
# so we do it with a regexp instead. This function is not used from
# _version.py.
keywords = {}
try:
f = open(versionfile_abs, "r")
for line in f.readlines():
if line.strip().startswith("git_refnames ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
keywords["refnames"] = mo.group(1)
if line.strip().startswith("git_full ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
keywords["full"] = mo.group(1)
if line.strip().startswith("git_date ="):
mo = re.search(r'=\s*"(.*)"', line)
if mo:
keywords["date"] = mo.group(1)
f.close()
except EnvironmentError:
pass
return keywords
@register_vcs_handler("git", "keywords")
def git_versions_from_keywords(keywords, tag_prefix, verbose):
"""Get version information from git keywords."""
if not keywords:
raise NotThisMethod("no keywords at all, weird")
date = keywords.get("date")
if date is not None:
# git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
# datestamp. However we prefer "%ci" (which expands to an "ISO-8601
# -like" string, which we must then edit to make compliant), because
# it's been around since git-1.5.3, and it's too difficult to
# discover which version we're using, or to work around using an
# older one.
date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
refnames = keywords["refnames"].strip()
if refnames.startswith("$Format"):
if verbose:
print("keywords are unexpanded, not using")
raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
refs = set([r.strip() for r in refnames.strip("()").split(",")])
# starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
# just "foo-1.0". If we see a "tag: " prefix, prefer those.
TAG = "tag: "
tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
if not tags:
# Either we're using git < 1.8.3, or there really are no tags. We use
# a heuristic: assume all version tags have a digit. The old git %d
# expansion behaves like git log --decorate=short and strips out the
# refs/heads/ and refs/tags/ prefixes that would let us distinguish
# between branches and tags. By ignoring refnames without digits, we
# filter out many common branch names like "release" and
# "stabilization", as well as "HEAD" and "master".
tags = set([r for r in refs if re.search(r'\d', r)])
if verbose:
print("discarding '%s', no digits" % ",".join(refs - tags))
if verbose:
print("likely tags: %s" % ",".join(sorted(tags)))
for ref in sorted(tags):
# sorting will prefer e.g. "2.0" over "2.0rc1"
if ref.startswith(tag_prefix):
r = ref[len(tag_prefix):]
if verbose:
print("picking %s" % r)
return {"version": r,
"full-revisionid": keywords["full"].strip(),
"dirty": False, "error": None,
"date": date}
# no suitable tags, so version is "0+unknown", but full hex is still there
if verbose:
print("no suitable tags, using unknown + full revision id")
return {"version": "0+unknown",
"full-revisionid": keywords["full"].strip(),
"dirty": False, "error": "no suitable tags", "date": None}
@register_vcs_handler("git", "pieces_from_vcs")
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
"""Get version from 'git describe' in the root of the source tree.
This only gets called if the git-archive 'subst' keywords were *not*
expanded, and _version.py hasn't already been rewritten with a short
version string, meaning we're inside a checked out source tree.
"""
GITS = ["git"]
if sys.platform == "win32":
GITS = ["git.cmd", "git.exe"]
out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
hide_stderr=True)
if rc != 0:
if verbose:
print("Directory %s not under git control" % root)
raise NotThisMethod("'git rev-parse --git-dir' returned error")
# if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
# if there isn't one, this yields HEX[-dirty] (no NUM)
describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
"--always", "--long",
"--match", "%s*" % tag_prefix],
cwd=root)
# --long was added in git-1.5.5
if describe_out is None:
raise NotThisMethod("'git describe' failed")
describe_out = describe_out.strip()
full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
if full_out is None:
raise NotThisMethod("'git rev-parse' failed")
full_out = full_out.strip()
pieces = {}
pieces["long"] = full_out
pieces["short"] = full_out[:7] # maybe improved later
pieces["error"] = None
# parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
# TAG might have hyphens.
git_describe = describe_out
# look for -dirty suffix
dirty = git_describe.endswith("-dirty")
pieces["dirty"] = dirty
if dirty:
git_describe = git_describe[:git_describe.rindex("-dirty")]
# now we have TAG-NUM-gHEX or HEX
if "-" in git_describe:
# TAG-NUM-gHEX
mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
if not mo:
# unparseable. Maybe git-describe is misbehaving?
pieces["error"] = ("unable to parse git-describe output: '%s'"
% describe_out)
return pieces
# tag
full_tag = mo.group(1)
if not full_tag.startswith(tag_prefix):
if verbose:
fmt = "tag '%s' doesn't start with prefix '%s'"
print(fmt % (full_tag, tag_prefix))
pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
% (full_tag, tag_prefix))
return pieces
pieces["closest-tag"] = full_tag[len(tag_prefix):]
# distance: number of commits since tag
pieces["distance"] = int(mo.group(2))
# commit: short hex revision ID
pieces["short"] = mo.group(3)
else:
# HEX: no tags
pieces["closest-tag"] = None
count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
cwd=root)
pieces["distance"] = int(count_out) # total number of commits
# commit date: see ISO-8601 comment in git_versions_from_keywords()
date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
cwd=root)[0].strip()
pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
return pieces
def plus_or_dot(pieces):
"""Return a + if we don't already have one, else return a ."""
if "+" in pieces.get("closest-tag", ""):
return "."
return "+"
def render_pep440(pieces):
"""Build up version string, with post-release "local version identifier".
Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
Exceptions:
1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"] or pieces["dirty"]:
rendered += plus_or_dot(pieces)
rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
if pieces["dirty"]:
rendered += ".dirty"
else:
# exception #1
rendered = "0+untagged.%d.g%s" % (pieces["distance"],
pieces["short"])
if pieces["dirty"]:
rendered += ".dirty"
return rendered
def render_pep440_pre(pieces):
"""TAG[.post.devDISTANCE] -- No -dirty.
Exceptions:
1: no tags. 0.post.devDISTANCE
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"]:
rendered += ".post.dev%d" % pieces["distance"]
else:
# exception #1
rendered = "0.post.dev%d" % pieces["distance"]
return rendered
def render_pep440_post(pieces):
"""TAG[.postDISTANCE[.dev0]+gHEX] .
The ".dev0" means dirty. Note that .dev0 sorts backwards
(a dirty tree will appear "older" than the corresponding clean one),
but you shouldn't be releasing software with -dirty anyways.
Exceptions:
1: no tags. 0.postDISTANCE[.dev0]
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"] or pieces["dirty"]:
rendered += ".post%d" % pieces["distance"]
if pieces["dirty"]:
rendered += ".dev0"
rendered += plus_or_dot(pieces)
rendered += "g%s" % pieces["short"]
else:
# exception #1
rendered = "0.post%d" % pieces["distance"]
if pieces["dirty"]:
rendered += ".dev0"
rendered += "+g%s" % pieces["short"]
return rendered
def render_pep440_old(pieces):
"""TAG[.postDISTANCE[.dev0]] .
The ".dev0" means dirty.
Eexceptions:
1: no tags. 0.postDISTANCE[.dev0]
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"] or pieces["dirty"]:
rendered += ".post%d" % pieces["distance"]
if pieces["dirty"]:
rendered += ".dev0"
else:
# exception #1
rendered = "0.post%d" % pieces["distance"]
if pieces["dirty"]:
rendered += ".dev0"
return rendered
def render_git_describe(pieces):
"""TAG[-DISTANCE-gHEX][-dirty].
Like 'git describe --tags --dirty --always'.
Exceptions:
1: no tags. HEX[-dirty] (note: no 'g' prefix)
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
if pieces["distance"]:
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
else:
# exception #1
rendered = pieces["short"]
if pieces["dirty"]:
rendered += "-dirty"
return rendered
def render_git_describe_long(pieces):
"""TAG-DISTANCE-gHEX[-dirty].
Like 'git describe --tags --dirty --always -long'.
The distance/hash is unconditional.
Exceptions:
1: no tags. HEX[-dirty] (note: no 'g' prefix)
"""
if pieces["closest-tag"]:
rendered = pieces["closest-tag"]
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
else:
# exception #1
rendered = pieces["short"]
if pieces["dirty"]:
rendered += "-dirty"
return rendered
def render(pieces, style):
"""Render the given version pieces into the requested style."""
if pieces["error"]:
return {"version": "unknown",
"full-revisionid": pieces.get("long"),
"dirty": None,
"error": pieces["error"],
"date": None}
if not style or style == "default":
style = "pep440" # the default
if style == "pep440":
rendered = render_pep440(pieces)
elif style == "pep440-pre":
rendered = render_pep440_pre(pieces)
elif style == "pep440-post":
rendered = render_pep440_post(pieces)
elif style == "pep440-old":
rendered = render_pep440_old(pieces)
elif style == "git-describe":
rendered = render_git_describe(pieces)
elif style == "git-describe-long":
rendered = render_git_describe_long(pieces)
else:
raise ValueError("unknown style '%s'" % style)
return {"version": rendered, "full-revisionid": pieces["long"],
"dirty": pieces["dirty"], "error": None,
"date": pieces.get("date")}
def get_versions():
"""Get version information or return default if unable to do so."""
# I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
# __file__, we can work backwards from there to the root. Some
# py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
# case we can only use expanded keywords.
cfg = get_config()
verbose = cfg.verbose
try:
return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
verbose)
except NotThisMethod:
pass
try:
root = os.path.realpath(__file__)
# versionfile_source is the relative path from the top of the source
# tree (where the .git directory might live) to this file. Invert
# this to find the root from __file__.
for i in cfg.versionfile_source.split('/'):
root = os.path.dirname(root)
except NameError:
return {"version": "0+unknown", "full-revisionid": None,
"dirty": None,
"error": "unable to find root of source tree",
"date": None}
try:
pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
return render(pieces, cfg.style)
except NotThisMethod:
pass
try:
if cfg.parentdir_prefix:
return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
except NotThisMethod:
pass
__version__ = "0.5.0"
return {"version": "0+unknown", "full-revisionid": None,
"dirty": None,
"error": "unable to compute version", "date": None}