[Debian-astro-commits] [python-cpl] 01/03: New upstream version 0.7.2
Ole Streicher
olebole at moszumanska.debian.org
Tue Feb 23 08:13:09 UTC 2016
This is an automated email from the git hooks/post-receive script.
olebole pushed a commit to branch debian
in repository python-cpl.
commit 38774b8b6e3de0d5cc5d1d8b55defce8e2bc74ea
Author: Ole Streicher <ole at aip.de>
Date: Mon Feb 22 09:47:19 2016 +0100
New upstream version 0.7.2
---
PKG-INFO | 7 +-
README.rst | 16 +++--
cpl/CPL_library.c | 2 +
cpl/CPL_library.h | 4 +-
cpl/cpl_api.h | 2 +-
cpl/dfs.py | 30 ++-------
cpl/esorex.py | 2 +-
cpl/frames.py | 5 +-
cpl/logger.py | 3 -
cpl/md5sum.py | 15 ++---
cpl/recipe.py | 15 +++--
cpl/result.py | 47 +++++++-------
cpl/run.py | 130 --------------------------------------
cpl/version.py | 2 +-
doc/install.rst | 9 +--
doc/{install.rst => install.rst~} | 0
setup.py | 4 +-
test/TestRecipe.py | 120 ++++++++++++++++++++++++-----------
18 files changed, 157 insertions(+), 256 deletions(-)
diff --git a/PKG-INFO b/PKG-INFO
index 0cedee7..f80ec8d 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,12 @@
Metadata-Version: 1.1
Name: python-cpl
-Version: 0.7
+Version: 0.7.2
Summary: Python interface for the ESO Common Pipeline Library
-Home-page: https://pypi.python.org/pypi/python-cpl/0.7
+Home-page: https://pypi.python.org/pypi/python-cpl/0.7.2
Author: Ole Streicher
Author-email: python-cpl at liska.ath.cx
License: GPL
-Download-URL: http://pypi.python.org/packages/source/p/python-cpl/python-cpl-0.7.tar.gz
+Download-URL: http://pypi.python.org/packages/source/p/python-cpl/python-cpl-0.7.2.tar.gz
Description: This module can list, configure and execute CPL-based recipes from Python
(python2 and python3). The input, calibration and output data can be
specified as FITS files or as ``astropy.io.fits`` objects in memory.
@@ -31,5 +31,4 @@ Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering :: Astronomy
-Requires: astropy
Provides: cpl
diff --git a/README.rst b/README.rst
index a9306f2..577ca4e 100644
--- a/README.rst
+++ b/README.rst
@@ -3,13 +3,15 @@ python-cpl
*Python interface for the Common Pipeline Library*
-.. image:: https://pypip.in/v/python-cpl/badge.png
+.. image:: https://img.shields.io/pypi/v/python-cpl.svg
:target: https://pypi.python.org/pypi/python-cpl
-.. image:: https://pypip.in/d/python-cpl/badge.png
+.. image:: https://img.shields.io/pypi/dm/python-cpl.svg
:target: https://pypi.python.org/pypi/python-cpl
-This module can list, configure and execute CPL-based recipes from Python
+Python-cpl is an `Astropy Affiliated Package <http://www.astropy.org/affiliated/>`_
+that can list, configure and execute recipes from `ESO data reduction
+pipelines <http://www.eso.org/sci/software/pipelines/>`_ from Python
(python2 and python3). The input, calibration and output data can be
specified as FITS files or as ``astropy.io.fits`` objects in memory.
@@ -21,13 +23,12 @@ the CPL is the ability to create data-reduction algorithms that run as plugins
(dynamic libraries). These are called "recipes" and are one of the main
aspects of the CPL data-reduction development environment.
-Python-cpl releases are `registered on PyPI
+Python-CPL releases are `registered on PyPI
<http://pypi.python.org/pypi/python-cpl>`_, and development is occurring at
the `project's github page <http://github.com/olebole/python-cpl>`_.
For installation instructions, see the
-`online documentation <http://cpl-python.readthedocs.org/en/master/install.html>`_
-or ``docs/install.rst`` in this source distribution.
+`online documentation <http://python-cpl.readthedocs.org/en/latest/install.html>`_.
The travis test status, coverage, and documentation build status
of the github repository is:
@@ -37,6 +38,9 @@ of the github repository is:
.. image:: https://coveralls.io/repos/olebole/python-cpl/badge.svg?branch=master
:target: https://coveralls.io/r/olebole/python-cpl?branch=master
+.. image:: https://landscape.io/github/olebole/python-cpl/master/landscape.svg?style=flat
+ :target: https://landscape.io/github/olebole/python-cpl/master
+
.. image:: https://readthedocs.org/projects/python-cpl/badge/?version=latest
:target: https://readthedocs.org/projects/python-cpl/?badge=latest
diff --git a/cpl/CPL_library.c b/cpl/CPL_library.c
index 3dd9541..aadd353 100644
--- a/cpl/CPL_library.c
+++ b/cpl/CPL_library.c
@@ -4,6 +4,8 @@
#include "CPL_library.h"
unsigned long supported_versions[] = {
+ CPL_VERSION(7,0,0),
+ CPL_VERSION(6,6,1),
CPL_VERSION(6,6,0),
CPL_VERSION(6,5,1),
CPL_VERSION(6,5,0),
diff --git a/cpl/CPL_library.h b/cpl/CPL_library.h
index fa42970..9880742 100644
--- a/cpl/CPL_library.h
+++ b/cpl/CPL_library.h
@@ -16,8 +16,8 @@
#if CPL_VERSION_CODE < CPL_VERSION(6,3,0)
#error CPL version too old. Minimum required version is 6.3.0.
#endif
-#if CPL_VERSION_CODE > CPL_VERSION(6,3,0)
-#warning Newer CPL version: check API compability with 6.3.0 at http://upstream-tracker.org/versions/cpl.html
+#if CPL_VERSION_CODE > CPL_VERSION(7,0,0)
+#warning Newer CPL version: check API compability with 7.0.0 at http://upstream-tracker.org/versions/cpl.html
#endif
extern unsigned long supported_versions[];
diff --git a/cpl/cpl_api.h b/cpl/cpl_api.h
index 6ce173a..bd303ab 100644
--- a/cpl/cpl_api.h
+++ b/cpl/cpl_api.h
@@ -36,7 +36,7 @@
#define CPL_VERSION_MINOR_CODE(code) (((code) >> 8) & 0xff)
#define CPL_VERSION_MICRO_CODE(code) ((code) & 0xff)
-#define CPL_VERSION_CODE CPL_VERSION(6,3,0)
+#define CPL_VERSION_CODE CPL_VERSION(7,0,0)
typedef int cpl_error_code, cpl_errorstate, cpl_boolean, cpl_frame_group,
cpl_parameter_mode, cpl_parameter_class, cpl_type, cpl_msg_severity;
diff --git a/cpl/dfs.py b/cpl/dfs.py
index ec3cb18..1300ebe 100644
--- a/cpl/dfs.py
+++ b/cpl/dfs.py
@@ -1,9 +1,7 @@
-import itertools
-import os
import sys
-try:
+try: # pragma: no cover
from astropy.io import fits
-except:
+except ImportError:
import pyfits as fits
import cpl
@@ -87,7 +85,7 @@ class ProcessingInfo(object):
accompanied with the MD5 sum.
'''
- def __init__(self, source, recno = -1, md5sums = None):
+ def __init__(self, source, recno = -1):
'''
:param source: Object pointing to the result file header
:type source: :class:`str` or :class:`astropy.io.fits.HDUList`
@@ -96,10 +94,6 @@ class ProcessingInfo(object):
:param recno: Record number. Optional. If not given, the last record
(with the highest record number) is used.
:type recno: :class:`int`
- :param md5sums: Dictionary with md5 sums as keys and complete file names
- as values to provide a full path for the raw and
- calibration frames. Optional.
- :type md5sums: :class:`dict`
'''
if isinstance(source, str):
header = fits.open(source)[0].header
@@ -133,8 +127,6 @@ class ProcessingInfo(object):
self.version = None
self.cpl_version = header.get('HIERARCH ESO PRO REC{0} DRS ID'.format(recno))
self.md5sum = header.get('DATAMD5')
- if md5sums and self.md5sum in md5sums:
- self.orig_filename = md5sums[self.md5sum]
self.md5sums = {}
self.calib = ProcessingInfo._get_rec_keys(header, recno, 'CAL', 'CATG', 'NAME')
for cat, md5 in ProcessingInfo._get_rec_keys(header, recno, 'CAL', 'CATG',
@@ -142,12 +134,8 @@ class ProcessingInfo(object):
if isinstance(md5, list):
for i, m in enumerate(md5):
if m is not None:
- if md5sums and m in md5sums:
- self.calib[cat][i] = md5sums[m]
self.md5sums[self.calib[cat][i]] = m
elif md5 is not None:
- if md5sums and md5 in md5sums:
- self.calib[cat] = md5sums[md5]
self.md5sums[self.calib[cat]] = md5
raw = ProcessingInfo._get_rec_keys(header, recno, 'RAW', 'CATG', 'NAME')
if raw:
@@ -158,12 +146,8 @@ class ProcessingInfo(object):
if isinstance(md5, list):
for i, m in enumerate(md5):
if m is not None:
- if md5sums and m in md5sums:
- self.raw[i] = md5sums[m]
self.md5sums[self.raw[i]] = m
elif md5 is not None:
- if md5sums and md5 in md5sums:
- self.raw = md5sums[md5]
self.md5sums[self.raw] = md5
else:
self.tag = None
@@ -224,7 +208,7 @@ class ProcessingInfo(object):
else:
m = max(len(n) for n in v)
for n in v:
- s += ' {0:<{width}} {1}\n'.format(n, m, k, width = m)
+ s += ' {0:<{width}} {1}\n'.format(n, m, width = m)
if self.raw is not None:
s += 'Input frames:\n'
if isinstance(self.raw, (str, unicode)):
@@ -304,7 +288,7 @@ class ProcessingInfo(object):
return {'true':True, 'false':False}.get(value, value)
@staticmethod
- def list(source, md5sums = None):
+ def list(source):
'''Get a list of all `ProcessingInfo` objects in the FITS header. The
list is sorted by the execution order.
@@ -316,14 +300,12 @@ class ProcessingInfo(object):
pi = []
for i in range(1, 2**16):
try:
- pi.append(ProcessingInfo(source, i, md5sums))
+ pi.append(ProcessingInfo(source, i))
except KeyError:
break
return pi
if __name__ == '__main__':
- import sys
-
for arg in sys.argv[1:]:
print('{0}\nfile: {1}'.format('-' * 72, arg))
pi = cpl.dfs.ProcessingInfo(arg)
diff --git a/cpl/esorex.py b/cpl/esorex.py
index 677c0b1..1ecd62f 100644
--- a/cpl/esorex.py
+++ b/cpl/esorex.py
@@ -169,7 +169,7 @@ class CplLogger(object):
@format.setter
def format(self, fmt):
- if fmt == None:
+ if fmt is None:
fmt = '%(asctime)s ' if self._time else ''
fmt += '[%(levelname)7s]'
fmt += '[%(threadName)s] ' if self._threadid else ' '
diff --git a/cpl/frames.py b/cpl/frames.py
index aba18e6..b54d2aa 100644
--- a/cpl/frames.py
+++ b/cpl/frames.py
@@ -1,9 +1,8 @@
from __future__ import absolute_import
import os
-import tempfile
-try:
+try: # pragma: no cover
from astropy.io import fits
-except:
+except ImportError:
import pyfits as fits
from . import md5sum
diff --git a/cpl/logger.py b/cpl/logger.py
index 7129ac9..658a353 100644
--- a/cpl/logger.py
+++ b/cpl/logger.py
@@ -3,12 +3,9 @@ import datetime
import logging
import os
import re
-import sys
import tempfile
import threading
-from . import CPL_recipe
-
class NullHandler(logging.Handler):
def emit(self, record):
pass
diff --git a/cpl/md5sum.py b/cpl/md5sum.py
index 90df125..d681c55 100644
--- a/cpl/md5sum.py
+++ b/cpl/md5sum.py
@@ -1,21 +1,20 @@
-import os
import hashlib
def datamd5(hdulist):
'''Calculate the MD5SUM of all data regions of a HDUList.
'''
- sum = hashlib.md5()
+ md5sum = hashlib.md5()
for hdu in hdulist:
if hdu.data is not None:
- sum.update(bytes(hdu.data.data))
+ md5sum.update(bytes(hdu.data.data))
pad = b'\0' * (2880 - hdu.data.nbytes % 2880)
- sum.update(pad)
- return sum.hexdigest()
+ md5sum.update(pad)
+ return md5sum.hexdigest()
def verify_md5(hdulist):
return hdulist[0].header.get('DATAMD5') == datamd5(hdulist)
def update_md5(hdulist):
- sum = datamd5(hdulist)
- hdulist[0].header['DATAMD5'] = (sum, 'MD5 checksum')
- return sum
+ md5sum = datamd5(hdulist)
+ hdulist[0].header['DATAMD5'] = (md5sum, 'MD5 checksum')
+ return md5sum
diff --git a/cpl/recipe.py b/cpl/recipe.py
index 9cdc556..dbaba54 100644
--- a/cpl/recipe.py
+++ b/cpl/recipe.py
@@ -7,9 +7,9 @@ import collections
import warnings
import textwrap
-try:
+try: # pragma: no cover
from astropy.io import fits
-except:
+except ImportError:
import pyfits as fits
from . import CPL_recipe
@@ -280,7 +280,8 @@ class Recipe(object):
@calib.setter
def calib(self, source = None):
if isinstance(source, str) or hasattr(source, 'read'):
- source = esorex.load_sof(source)
+ from .esorex import load_sof
+ source = load_sof(source)
self._calib = FrameList(self, source)
@calib.deleter
@@ -345,7 +346,8 @@ class Recipe(object):
@param.setter
def param(self, source = None):
if isinstance(source, str) or hasattr(source, 'read'):
- source = esorex.load_rc(source)
+ from .esorex import load_rc
+ source = load_rc(source)
self._param = ParameterList(self, source)
@param.deleter
@@ -407,7 +409,6 @@ class Recipe(object):
(``threaded = True``) and an exception occurs, this exception is
raised whenever result fields are accessed.
'''
- tmpfiles = []
threaded = ndata.get('threaded', self.threaded)
mtrace = ndata.get('mtrace', self.mtrace)
loglevel = ndata.get('loglevel')
@@ -451,7 +452,7 @@ class Recipe(object):
def _exec(self, output_dir, parlist, framelist, runenv,
input_len, logger, output_format, delete, mtrace):
try:
- return Result(self._recipe.frameConfig(), output_dir,
+ return Result(output_dir,
self._recipe.run(output_dir, parlist, framelist,
list(runenv.items()),
logger.logfile, logger.level,
@@ -567,7 +568,7 @@ class Recipe(object):
libs = [ ]
path = Recipe.path.split(':') if isinstance(Recipe.path, str) else Recipe.path
for p in path:
- for root, dir, files in os.walk(p):
+ for root, d, files in os.walk(p):
libs += [ os.path.join(root, f)
for f in files if f.endswith('.so') ]
return libs
diff --git a/cpl/result.py b/cpl/result.py
index 86f90c6..dbd3623 100644
--- a/cpl/result.py
+++ b/cpl/result.py
@@ -3,13 +3,13 @@ import os
import signal
import logging
-try:
+try: # pragma: no cover
from astropy.io import fits
-except:
+except ImportError:
import pyfits as fits
class Result(object):
- def __init__(self, recipedefs, dir, res, input_len = 0, logger = None,
+ def __init__(self, directory, res, input_len = 0, logger = None,
output_format = fits.HDUList):
'''Build an object containing all result frames.
@@ -45,7 +45,7 @@ class Result(object):
more sophisticated. And this is not usable for non-MUSE recipes
anyway. So, we will skip this to probably some distant future.
'''
- self.dir = os.path.abspath(dir)
+ self.dir = os.path.abspath(directory)
logger.join()
if res[2][0]:
raise CplError(res[2][0], res[1], logger)
@@ -142,7 +142,7 @@ class CplError(Exception):
.. seealso:: :class:`cpl.logger.LogList`
- .. attribute:: next
+ .. attribute:: next_error
Next error, or :obj:`None`.
@@ -150,7 +150,7 @@ class CplError(Exception):
def __init__(self, retval, res, logger = None):
self.retval = retval
self.log = logger.entries if logger else None
- self.next = None
+ self.next_error = None
if not res:
self.code, self.msg, self.file, self.line, self.function = (
None, None, None, None, None)
@@ -158,18 +158,20 @@ class CplError(Exception):
self.code, self.msg, self.file, self.line, self.function = res[0]
o = self
for r in res[1:]:
- o.next = CplError(retval, [ r ], logger)
- o = o.next
+ o.next_error = CplError(retval, [ r ], logger)
+ o = o.next_error
def __iter__(self):
- class Iter:
+ class Iter(object):
current = self
- def next(self):
+ def __next__(self):
if Iter.current is None:
raise StopIteration
s = Iter.current
- Iter.current = Iter.current.next
+ Iter.current = Iter.current.next_error
return s
+ def next(self):
+ return self.__next__()
return Iter()
def __str__(self):
@@ -179,8 +181,8 @@ class CplError(Exception):
s = "%s (%i) in %s() (%s:%i)" % (self.msg, self.code,
self.function, self.file,
self.line)
- if self.next:
- for e in self.next:
+ if self.next_error:
+ for e in self.next_error:
s += "\n %s (%i) in %s() (%s:%i)" % (e.msg, e.code,
e.function, e.file,
e.line)
@@ -286,10 +288,10 @@ class RecipeCrash(Exception):
for e in self.elements ]
Exception.__init__(self, str(self))
- def _add_variable(self, vars, line):
+ def _add_variable(self, variables, line):
s = line.strip().split('=', 1)
if len(s) > 1:
- vars[s[0].strip()] = s[1].strip()
+ variables[s[0].strip()] = s[1].strip()
def _parse_function_line(self, line):
s = line.split()
@@ -317,21 +319,20 @@ class RecipeCrash(Exception):
log.error('Recipe crashed. Traceback (most recent call last):')
for e in self.elements:
logc = logging.getLogger('%s.%s' % (logger.name, e.func))
- logc.error(' File "%s", %sin %s\n' % (
- e.filename,
- 'line %i, ' % e.line if e.line else '',
- e.func))
+ logc.error(' File "%s", %sin %s\n',e.filename,
+ 'line %i, ' % e.line if e.line else '',
+ e.func)
if os.path.exists(e.filename) and e.line:
- logc.error(' %s\n'
- % open(e.filename).readlines()[e.line-1].strip())
+ logc.error(' %s\n',
+ open(e.filename).readlines()[e.line-1].strip())
if e.params:
logc.error(' Parameters:')
for p, v in e.params.items():
- logc.error(' %s = %s' % (p, v))
+ logc.error(' %s = %s', p, v)
if e.localvars:
logc.error(' Local variables:')
for p, v in e.localvars.items():
- logc.error(' %s = %s' % (p, v))
+ logc.error(' %s = %s', p, v)
log.error(RecipeCrash.signals.get(self.signal,
'%s: Unknown' % str(self.signal)))
diff --git a/cpl/run.py b/cpl/run.py
deleted file mode 100644
index 04c113c..0000000
--- a/cpl/run.py
+++ /dev/null
@@ -1,130 +0,0 @@
-import cpl
-import sys
-import logging
-
-from optparse import OptionParser, OptionGroup
-
-cpl.esorex.init()
-
-for i in range(1, len(sys.argv)):
- if not sys.argv[i].startswith('--'):
- recipe = cpl.Recipe(sys.argv[i])
- recipe.output_dir = '.'
- del sys.argv[i]
- break
-else:
- recipe = None
-
-parser = OptionParser(prog='%s %s' % (sys.argv[0], recipe.__name__),
- version = recipe.__version__,
- description=recipe.description[0],
- epilog=recipe.description[1] + '\n') if recipe else \
- OptionParser(prog=sys.argv[0],
- version=cpl.__version__)
-
-def output_dir_callback(option, opt, value, parser):
- recipe.output_dir = value
-
-parser.add_option('--output-dir', action = 'callback',
- type='str', help =
- 'The directory where the product files will be written',
- callback = output_dir_callback)
-
-log = logging.getLogger()
-log.setLevel(logging.INFO)
-cpl.esorex.msg.level = logging.ERROR
-
-def logfile_callback(option, opt, value, parser):
- ch = logging.FileHandler(value)
- ch.setLevel(logging.DEBUG)
- ch.setFormatter(logging.Formatter(
- "%(asctime)s [%(levelname)s] %(name)s: %(message)s"))
- log.addHandler(ch)
-
-parser.add_option('--log-file', action = 'callback',
- type='str', help = 'Filename of logfile',
- callback = logfile_callback)
-
-def loglevel_callback(option, opt, value, parser):
- levels = {'debug':logging.DEBUG, 'info':logging.INFO,
- 'warning':logging.warning, 'error':logging.ERROR }
- log.setLevel(levels[value])
-
-parser.add_option('--log-level', action = 'callback',
- type='str', help = 'Controls the severity level of '
- 'messages that will be printed to the logfile.',
- callback = loglevel_callback)
-
-def msglevel_callback(option, opt, value, parser):
- levels = {'debug':logging.DEBUG, 'info':logging.INFO,
- 'warning':logging.warning, 'error':logging.ERROR }
- cpl.esorex.msg.level = levels[value]
-
-parser.add_option('--msg-level', action = 'callback',
- type='str', help = 'Controls the severity level of '
- 'messages that will be printed to the terminal.',
- callback = msglevel_callback)
-
-def tag_callback(option, opt, value, parser):
- recipe.tag = value
-
-
-def param_callback(option, opt, value, parser, p):
- p.value = value
-
-def calib_callback(option, opt, value, parser, c):
- p.frame = value
-
-types = { bool:'string', str:'string', int:'int', float:'float' }
-
-if recipe:
- parser.add_option('--tag', action = 'callback',
- type='str', help =
- 'Input file tag %s' % repr(recipe.tags),
- callback = tag_callback)
-
- group = OptionGroup(parser, 'Recipe parameters')
- for p in recipe.param:
- group.add_option('--%s' % p.name, action = 'callback',
- type=types.get(p.default.__class__),
- help = '%s [%s]' % (p.__doc__, p.default),
- callback = param_callback, callback_args = (p,))
- parser.add_option_group(group)
-
- if len(recipe.calib) > 0:
- group = OptionGroup(parser, 'Calibration frames')
-
- for f in recipe.calib:
- help = ''
- if f.min < 1:
- help = 'optional'
- elif f.min > 1:
- help = 'min %i' % f.min
- else:
- help = 'required'
- if f.max != 1:
- if help:
- help += ', '
- help += 'may be repeated'
- group.add_option('--%s' % f.tag, action='callback',
- type = 'string', help = help,
- callback = calib_callback,
- callback_args = (f,))
- parser.add_option_group(group)
-
-(option, args) = parser.parse_args(sys.argv)
-
-if not args[1:]:
- parser.print_help()
- sys.exit()
-
-try:
- recipe(args[1:])
-except cpl.result.RecipeCrash as ex:
- log.exception(ex)
- print(repr(ex))
-except cpl.result.CplError as ex:
- log.exception(ex)
- print(repr(ex))
-
-
diff --git a/cpl/version.py b/cpl/version.py
index 3df35ae..7b26f93 100644
--- a/cpl/version.py
+++ b/cpl/version.py
@@ -1,4 +1,4 @@
-version = '0.7'
+version = '0.7.2'
author = 'Ole Streicher'
email = 'python-cpl at liska.ath.cx'
license_ = 'GPL'
diff --git a/doc/install.rst b/doc/install.rst
index 9d052b0..9a06e09 100644
--- a/doc/install.rst
+++ b/doc/install.rst
@@ -17,10 +17,11 @@ On Debian and debian-based systems (Ubuntu, Mint), python-cpl can be installed w
apt-get install python-cpl
-Python CPL comes with the Ubuntu distribution since 12.04.
-Debian packages are in `Wheezy (Debian 7) <http://packages.debian.org/wheezy/python-cpl>`_,
-`Wheezy (Debian 8) <http://packages.debian.org/jessie/python-cpl>`_, and
-`Testing <http://packages.debian.org/testing/python-cpl>`_
+Python CPL comes with the `Ubuntu <packages.ubuntu.com/python-cpl>`_
+distribution since 12.04. Debian packages are in `Wheezy (Debian 7)
+<http://packages.debian.org/wheezy/python-cpl>`_, `Squeeze (Debian 8)
+<http://packages.debian.org/jessie/python-cpl>`_, and `Testing
+<http://packages.debian.org/testing/python-cpl>`_
Source code
-----------
diff --git a/doc/install.rst b/doc/install.rst~
similarity index 100%
copy from doc/install.rst
copy to doc/install.rst~
diff --git a/setup.py b/setup.py
index 6a4b3ba..4369ed8 100644
--- a/setup.py
+++ b/setup.py
@@ -5,7 +5,7 @@ from pkg_resources import require, DistributionNotFound
author = 'Ole Streicher'
email = 'python-cpl at liska.ath.cx'
license_ = 'GPL'
-cpl_version = '0.7'
+cpl_version = '0.7.2'
description = "Python interface for the ESO Common Pipeline Library"
long_description = '''This module can list, configure and execute CPL-based recipes from Python
(python2 and python3). The input, calibration and output data can be
@@ -67,7 +67,7 @@ setup(
url = 'https://pypi.python.org/pypi/%s/%s' % (pkgname, cpl_version),
download_url = '%s/%s-%s.tar.gz' % (baseurl, pkgname, cpl_version),
classifiers = classifiers,
- requires = [ required ],
+ install_requires = [ required ],
provides = ['cpl'],
packages = ['cpl'],
ext_modules = [module1]
diff --git a/test/TestRecipe.py b/test/TestRecipe.py
index 799fd35..3586c87 100644
--- a/test/TestRecipe.py
+++ b/test/TestRecipe.py
@@ -14,35 +14,45 @@ cpl.Recipe.memory_mode = 0
recipe_name = 'rtest'
raw_tag = 'RRRECIPE_DOCATG_RAW'
-
-def create_recipe(name):
- cname = name + ".c"
- oname = name + '.o'
- soname = name + '.so'
- env = {
+rtest_esorexrc = '''# example RC file
+iiinstrument.rtest.string_option = more
+iiinstrument.rtest.bool_option = False
+iiinstrument.rtest.float_option = 1.125
+iiinstrument.rtest.int_option = -2
+iiinstrument.rtest.enum_option = second
+iiinstrument.rtest.range_option = 0.5
+iiinstrument.rtest.dotted.opt = 1
+'''
+
+def create_recipe(name, builddir):
+ var = {
'CC': os.getenv("CC", "gcc"),
'CPPFLAGS': os.getenv("CPPFLAGS", ""),
'CFLAGS': os.getenv("CFLAGS", ""),
'LDFLAGS': os.getenv("LDFLAGS", ""),
'LIBS': "-lcplcore -lcpldfs",
- 'cname': cname,
- 'oname': oname,
- 'soname': soname,
+ 'cname': os.path.join(os.path.dirname(__file__), name + ".c"),
+ 'oname': os.path.join(builddir, name + '.o'),
+ 'soname': os.path.join(builddir, name + '.so'),
}
- if (not os.path.exists(soname) or
- os.path.getmtime(soname) <= os.path.getmtime(cname)):
- os.system("{CC} {CPPFLAGS} {CFLAGS} -fPIC -c {cname}".format(**env))
- os.system("{CC} {LDFLAGS} -shared -o {soname} {oname} {LIBS}".format(**env))
- os.remove(oname)
-
+ os.system("{CC} {CPPFLAGS} {CFLAGS} -fPIC -c -o {oname} {cname}".format(**var))
+ os.system("{CC} {LDFLAGS} -shared -o {soname} {oname} {LIBS}".format(**var))
+ os.remove(var['oname'])
+
class CplTestCase(unittest.TestCase):
def setUp(self):
- cpl.Recipe.path = os.path.dirname(os.path.abspath(__file__))
+ unittest.TestCase.setUp(self)
+ self.temp_dir = tempfile.mkdtemp()
+ create_recipe(recipe_name, self.temp_dir)
+ cpl.Recipe.path = self.temp_dir
+
+ def tearDown(self):
+ unittest.TestCase.tearDown(self)
+ shutil.rmtree(self.temp_dir)
class RecipeTestCase(CplTestCase):
def setUp(self):
CplTestCase.setUp(self)
- self.temp_dir = tempfile.mkdtemp()
self.recipe = cpl.Recipe(recipe_name)
self.recipe.temp_dir = self.temp_dir
self.recipe.tag = raw_tag
@@ -53,9 +63,6 @@ class RecipeTestCase(CplTestCase):
self.raw_frame[0].header['HIERARCH ESO DET DIT'] = 0.0
self.raw_frame[0].header['HIERARCH ESO PRO CATG'] = raw_tag
- def tearDown(self):
- shutil.rmtree(self.temp_dir)
-
class RecipeStatic(CplTestCase):
def test_list(self):
'''List available recipes'''
@@ -84,8 +91,8 @@ class RecipeStatic(CplTestCase):
def test_create_recipe_filename(self):
'''Create a recipe specified by a the name and the filename'''
- recipe = cpl.Recipe(recipe_name, filename = os.path.join(
- os.path.dirname(os.path.abspath(__file__)),'rtest.so'))
+ recipe = cpl.Recipe(recipe_name,
+ filename = os.path.join(self.temp_dir, 'rtest.so'))
self.assertTrue(isinstance(recipe, cpl.Recipe))
def test_create_recipe_wrong_filename(self):
@@ -240,6 +247,17 @@ class RecipeParams(RecipeTestCase):
self.assertEqual(self.recipe.param.floatopt.value, 1.5)
self.assertEqual(self.recipe.param.boolopt.value, True)
+ def test_param_load_from_esorexrc(self):
+ '''Load parameters from an Esorex .rc file'''
+ self.recipe.param = rtest_esorexrc
+ self.assertEqual(self.recipe.param.stropt.value, 'more')
+ self.assertEqual(self.recipe.param.boolopt.value, False)
+ self.assertEqual(self.recipe.param.floatopt.value, 1.125)
+ self.assertEqual(self.recipe.param.intopt.value, -2)
+ self.assertEqual(self.recipe.param.enumopt.value, 'second')
+ self.assertEqual(self.recipe.param.rangeopt.value, 0.5)
+ self.assertEqual(self.recipe.param.dot.opt.value, 1)
+
def test_delete(self):
'''Delete all parameter values to reset to default'''
self.recipe.param.boolopt.value = True
@@ -269,6 +287,11 @@ class RecipeCalib(RecipeTestCase):
self.recipe.calib = { 'FLAT':'flat2.fits' }
self.assertEqual(self.recipe.calib.FLAT.frames, 'flat2.fits')
+ def test_param_load_from_esorexsof(self):
+ '''Load calibration from an Esorex SOF file'''
+ self.recipe.calib = 'flat.fits FLAT\n'
+ self.assertEqual(self.recipe.calib.FLAT.frames, 'flat.fits')
+
def test_del(self):
'''Delete a calibration frame set'''
self.recipe.calib.FLAT = 'flat.fits'
@@ -578,17 +601,17 @@ class RecipeExec(RecipeTestCase):
len('9d123996fa9a7bda315d07e063043454'))
class RecipeCrashing(RecipeTestCase):
- def test_corrupted(self):
+ def _test_corrupted(self):
'''Handling of recipe crashes because of corrupted memory'''
self.recipe.param.crashing = 'free'
self.assertRaises(cpl.RecipeCrash, self.recipe, self.raw_frame)
- def test_segfault(self):
+ def _test_segfault(self):
'''Handling of recipe crashes because of segmentation fault'''
self.recipe.param.crashing = 'segfault'
self.assertRaises(cpl.RecipeCrash, self.recipe, self.raw_frame)
- def test_cleanup_after_crash(self):
+ def _test_cleanup_after_crash(self):
'''Test that a second run after a crash will succeed'''
output_dir = os.path.join(self.temp_dir, 'out')
self.recipe.output_dir = output_dir
@@ -603,6 +626,7 @@ class RecipeRes(RecipeTestCase):
self.res = self.recipe(self.raw_frame)
def tearDown(self):
+ RecipeTestCase.tearDown(self)
try:
res.THE_PRO_CATG_VALUE.close()
except:
@@ -618,6 +642,15 @@ class RecipeRes(RecipeTestCase):
self.assertTrue(isinstance(self.res['THE_PRO_CATG_VALUE'],
fits.HDUList))
+ def test_in(self):
+ '''Check whether a tag is part of the result'''
+ self.assertTrue('THE_PRO_CATG_VALUE' in self.res)
+ self.assertFalse('Anothervalue' in self.res)
+
+ def test_keyerror(self):
+ '''Accessing an inexisting value'''
+ self.assertRaises(KeyError, lambda val: self.res[val], 'Anothervalue')
+
def test_len(self):
'''Length of the result'''
self.assertEqual(len(self.res), 1)
@@ -629,15 +662,10 @@ class RecipeRes(RecipeTestCase):
self.assertTrue(isinstance(hdu, fits.HDUList))
class RecipeEsorex(CplTestCase):
- def setUp(self):
- CplTestCase.setUp(self)
- self.temp_dir = tempfile.mkdtemp()
-
def tearDown(self):
CplTestCase.tearDown(self)
cpl.esorex.msg.level = cpl.esorex.msg.OFF
cpl.esorex.log.level = cpl.esorex.msg.OFF
- shutil.rmtree(self.temp_dir)
def test_read_sof(self):
'''Read a SOF file'''
@@ -656,12 +684,15 @@ class RecipeEsorex(CplTestCase):
def test_read_rc(self):
'''Read an EsoRec .rc file'''
- rcfile = '# environment variable lambda_low.\n' \
- 'muse.muse_sky.lambda_low=4.65e+03\n' \
- 'muse.muse_sky.lambda_high=9.3e+03\n'
- self.assertEqual(cpl.esorex.load_rc(rcfile),
- { 'muse.muse_sky.lambda_low': '4.65e+03',
- 'muse.muse_sky.lambda_high': '9.3e+03'})
+ self.assertEqual(cpl.esorex.load_rc(rtest_esorexrc),
+ { 'iiinstrument.rtest.string_option': 'more',
+ 'iiinstrument.rtest.bool_option': 'False',
+ 'iiinstrument.rtest.float_option': '1.125',
+ 'iiinstrument.rtest.int_option': '-2',
+ 'iiinstrument.rtest.enum_option': 'second',
+ 'iiinstrument.rtest.range_option': '0.5',
+ 'iiinstrument.rtest.dotted.opt': '1',
+ })
def test_esorex_init(self):
'''Init CPL from an esorex.rc file'''
@@ -880,6 +911,11 @@ class RecipeLog(RecipeTestCase):
# Check that we can read error messages
self.assertNotEqual(len(res.log.error), 0)
self.assertTrue(isinstance(res.log.error[0], str))
+ # Check that we can convert the error to a string
+ self.assertTrue(isinstance(res.__str__(), str))
+ # Check that we can iterate over error messages
+ for r in res:
+ self.assertTrue(isinstance(res, cpl.CplError))
class ProcessingInfo(RecipeTestCase):
def setUp(self):
@@ -898,6 +934,7 @@ class ProcessingInfo(RecipeTestCase):
self.pinfo = cpl.dfs.ProcessingInfo(self.res)
def tearDown(self):
+ RecipeTestCase.tearDown(self)
try:
self.res.close()
except:
@@ -946,6 +983,15 @@ class ProcessingInfo(RecipeTestCase):
md5sum = self.res[0].header.get('HIERARCH ESO PRO REC1 CAL1 DATAMD5')
self.assertEqual(md5sum, self.pinfo.md5sums[self.pinfo.calib['FLAT']])
-create_recipe(recipe_name)
+ def test_recipe(self):
+ '''Recreate and configure the recipe'''
+ recipe = self.pinfo.create_recipe()
+ self.assertTrue(isinstance(recipe, cpl.Recipe))
+ self.assertEqual(len(recipe.calib), 1)
+ self.assertEqual(recipe.calib.FLAT.frames[-5:], '.fits')
+ self.assertEqual(recipe.__name__, self.recipe.__name__)
+ self.assertEqual(recipe.version[0], self.recipe.version[0])
+ self.assertEqual(len(recipe.param), len(self.recipe.param))
+
if __name__ == '__main__':
unittest.main()
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-astro/packages/python-cpl.git
More information about the Debian-astro-commits
mailing list