[SCM] Control pipeline recipes from the European Southern Observatory branch, upstream, updated. upstream/0.3.5.1-5-gcb4a635
Ole Streicher
debian at liska.ath.cx
Mon Nov 26 10:57:17 UTC 2012
The following commit has been merged in the upstream branch:
commit cb4a635b5d311c0d99a85175dd026554f7e2b194
Author: Ole Streicher <debian at liska.ath.cx>
Date: Mon Nov 26 11:57:03 2012 +0100
New upstream version 0.4
diff --git a/PKG-INFO b/PKG-INFO
index 3447f4e..d2fef1b 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,12 +1,53 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: python-cpl
-Version: 0.3.8
+Version: 0.4
Summary: Python interface for the Common Pipeline Library.
-Home-page: http://www.aip.de/~oles/python-cpl/
+Home-page: http://www.aip.de/~oles/python-cpl
Author: Ole Streicher
Author-email: python-cpl at liska.ath.cx
License: GPL
-Description: Non-official library to access CPL modules via Python.
- It is not meant as part of the MUSE pipeline software, but
- may be useful for testing.
+Download-URL: http://www.aip.de/~oles/python-cpl/python-cpl-0.4.tar.gz
+Description: This module can list, configure and execute CPL-based recipes from Python.
+ The input, calibration and output data can be specified as FITS files
+ or as pyfits objects in memory.
+
+ The Common Pipeline Library (CPL) comprises a set of ISO-C libraries that
+ provide a comprehensive, efficient and robust software toolkit. It forms a
+ basis for the creation of automated astronomical data-reduction tasks. One of
+ the features provided by 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. More information about the CPL can be found here:
+
+ http://www.eso.org/sci/software/cpl/
+
+ The interface may be used to run ESO pipeline recipes linked to CPL
+ versions 4.0 to 6.2.
+
+ Build instructions
+ ------------------
+
+ python-cpl requires:
+
+ - Python 2.6 or later
+ - pyfits
+
+ python-cpl uses the standard Python distutils system to build and install
+ itself. From the command line run::
+
+ python setup.py install
+
+ to install python-cpl.
Platform: UNKNOWN
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Science/Research
+Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
+Classifier: Operating System :: MacOS :: MacOS X
+Classifier: Operating System :: POSIX
+Classifier: Operating System :: Unix
+Classifier: Programming Language :: C
+Classifier: Programming Language :: Python
+Classifier: Programming Language :: Python :: 2
+Classifier: Topic :: Scientific/Engineering :: Astronomy
+Requires: pyfits
+Provides: cpl
diff --git a/README b/README
index 4b42c11..0764987 100644
--- a/README
+++ b/README
@@ -1,29 +1,33 @@
-This subdir contains an non-official library to access CPL modules via
-Python. It is not meant as part of the MUSE pipeline software, but may be
-useful for testing.
+Python interface for the Common Pipeline Library.
-Installation
-============
+This module can list, configure and execute CPL-based recipes from Python.
+The input, calibration and output data can be specified as FITS files
+or as pyfits objects in memory.
-1. Check requirements:
- - CPL 5.X (Esorex is not needed)
- - Python 2.6
- - pyfits
+The Common Pipeline Library (CPL) comprises a set of ISO-C libraries that
+provide a comprehensive, efficient and robust software toolkit. It forms a
+basis for the creation of automated astronomical data-reduction tasks. One of
+the features provided by 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. More information about the CPL can be found here:
+
+ http://www.eso.org/sci/software/cpl/
-2. Determine where to put the compiled python package. Standard for
- compilations is /usr/local.
+The interface may be used to run ESO pipeline recipes linked to CPL
+versions 4.0 to 6.2.
-3. In this directory, run
+Build instructions
+------------------
- python setup.py install --prefix=<PREFIX>
+python-cpl requires:
- where the prefix determines the path for the compiled package. The package
- will be installed in the subdir lib/python2.6/site-packages
- (lib64/python2.6/site-packages on 64 bit systems) of <PREFIX>
+ - Python 2.6 or later
+ - pyfits
- To specify non-standard include and library paths for CPL, the environment
- variables LIBRARY_PATH and INCLUDE_PATH may be used.
+python-cpl uses the standard Python distutils system to build and install
+itself. From the command line run::
-4. Add the directory <PREFIX>/lib[64]/python2.6/site-packages to your
- environment variable PYTHONPATH.
+ python setup.py install
+to install python-cpl.
diff --git a/cpl/CPL_library.c b/cpl/CPL_library.c
new file mode 100644
index 0000000..cc9fcbf
--- /dev/null
+++ b/cpl/CPL_library.c
@@ -0,0 +1,214 @@
+#include <stdlib.h>
+#include <dlfcn.h>
+
+#include "CPL_library.h"
+
+unsigned long supported_versions[] = {
+ CPL_VERSION(6,2,0),
+ CPL_VERSION(6,1,1),
+ CPL_VERSION(6,0,1),
+ CPL_VERSION(6,0,0),
+ CPL_VERSION(5,3,1),
+ CPL_VERSION(5,2,0),
+ CPL_VERSION(5,1,0),
+ CPL_VERSION(5,0,1),
+ CPL_VERSION(5,0,0),
+ CPL_VERSION(4,2,0),
+ CPL_VERSION(4,1,0),
+ CPL_VERSION(4,0,1),
+ CPL_VERSION(4,0,0),
+ 0
+};
+
+static cpl_library_t **libraries = NULL;
+
+/* This module provides all needed functions to run a recipe from the
+ framework. These functions are extracted from the recipe shared lib
+ (resp. the CPL linked to that) by their names. I checked that the API
+ didn't change from CPL 4.0 which is now the minimal supported version here.
+
+ Since some constants changed over the time, all used constants are
+ also included in the structure. The constants are set directly depending on
+ the CPL version number.
+
+ Note that beta releases have to be taken very cautiously here since they
+ may contain incompatible changes here.
+*/
+
+cpl_library_t *create_library(const char *fname) {
+ void *handle = dlopen(fname, RTLD_LAZY);
+ if (handle == NULL) {
+ return NULL;
+ }
+
+ char *error = dlerror();
+ typeof(cpl_init) *init = dlsym(handle, "cpl_init");
+ error = dlerror();
+ if (error != NULL) {
+ dlclose(handle);
+ return NULL;
+ }
+
+ if (libraries == NULL) {
+ libraries = malloc(sizeof(cpl_library_t *));
+ libraries[0] = NULL;
+ }
+
+ int i;
+ for (i = 0; libraries[i] != NULL; i++) {
+ if (init == libraries[i]->init) {
+ dlclose(handle);
+ return libraries[i];
+ }
+ }
+
+ cpl_library_t *cpl = malloc(sizeof(cpl_library_t));
+ cpl->init = init;
+
+ cpl->get_description = dlsym(handle, "cpl_get_description");
+ cpl->memory_dump = dlsym(handle, "cpl_memory_dump");
+ cpl->memory_is_empty = dlsym(handle, "cpl_memory_is_empty");
+ cpl->free = dlsym(handle, "cpl_free");
+
+ cpl->plugin_get_author = dlsym(handle, "cpl_plugin_get_author");
+ cpl->plugin_get_copyright = dlsym(handle, "cpl_plugin_get_copyright");
+ cpl->plugin_get_deinit = dlsym(handle, "cpl_plugin_get_deinit");
+ cpl->plugin_get_description = dlsym(handle, "cpl_plugin_get_description");
+ cpl->plugin_get_email = dlsym(handle, "cpl_plugin_get_email");
+ cpl->plugin_get_exec = dlsym(handle, "cpl_plugin_get_exec");
+ cpl->plugin_get_init = dlsym(handle, "cpl_plugin_get_init");
+ cpl->plugin_get_name = dlsym(handle, "cpl_plugin_get_name");
+ cpl->plugin_get_synopsis = dlsym(handle, "cpl_plugin_get_synopsis");
+ cpl->plugin_get_version = dlsym(handle, "cpl_plugin_get_version");
+ cpl->plugin_get_version_string = dlsym(handle, "cpl_plugin_get_version_string");
+ cpl->pluginlist_delete = dlsym(handle, "cpl_pluginlist_delete");
+ cpl->pluginlist_find = dlsym(handle, "cpl_pluginlist_find");
+ cpl->pluginlist_get_first = dlsym(handle, "cpl_pluginlist_get_first");
+ cpl->pluginlist_get_next = dlsym(handle, "cpl_pluginlist_get_next");
+ cpl->pluginlist_new = dlsym(handle, "cpl_pluginlist_new");
+
+ cpl->dfs_update_product_header = dlsym(handle, "cpl_dfs_update_product_header");
+
+ cpl->error_get_code = dlsym(handle, "cpl_error_get_code");
+ cpl->error_get_file = dlsym(handle, "cpl_error_get_file");
+ cpl->error_get_function = dlsym(handle, "cpl_error_get_function");
+ cpl->error_get_line = dlsym(handle, "cpl_error_get_line");
+ cpl->error_get_message = dlsym(handle, "cpl_error_get_message");
+ cpl->error_reset = dlsym(handle, "cpl_error_reset");
+ cpl->error_set_message_macro = dlsym(handle, "cpl_error_set_message_macro");
+ cpl->errorstate_dump = dlsym(handle, "cpl_errorstate_dump");
+ cpl->errorstate_get = dlsym(handle, "cpl_errorstate_get");
+
+ cpl->frame_get_filename = dlsym(handle, "cpl_frame_get_filename");
+ cpl->frame_get_group = dlsym(handle, "cpl_frame_get_group");
+ cpl->frame_get_tag = dlsym(handle, "cpl_frame_get_tag");
+ cpl->frame_new = dlsym(handle, "cpl_frame_new");
+ cpl->frame_set_filename = dlsym(handle, "cpl_frame_set_filename");
+ cpl->frame_set_tag = dlsym(handle, "cpl_frame_set_tag");
+ cpl->frameset_delete = dlsym(handle, "cpl_frameset_delete");
+ cpl->frameset_get_frame = dlsym(handle, "cpl_frameset_get_frame");
+ cpl->frameset_get_size = dlsym(handle, "cpl_frameset_get_size");
+ cpl->frameset_insert = dlsym(handle, "cpl_frameset_insert");
+ cpl->frameset_new = dlsym(handle, "cpl_frameset_new");
+
+ cpl->msg_error = dlsym(handle, "cpl_msg_error");
+ cpl->msg_set_level = dlsym(handle, "cpl_msg_set_level");
+ cpl->msg_set_log_level = dlsym(handle, "cpl_msg_set_log_level");
+ cpl->msg_set_log_name = dlsym(handle, "cpl_msg_set_log_name");
+ cpl->msg_stop_log = dlsym(handle, "cpl_msg_stop_log");
+
+ cpl->parameter_get_alias = dlsym(handle, "cpl_parameter_get_alias");
+ cpl->parameter_get_class = dlsym(handle, "cpl_parameter_get_class");
+ cpl->parameter_get_context = dlsym(handle, "cpl_parameter_get_context");
+ cpl->parameter_get_default_bool = dlsym(handle, "cpl_parameter_get_default_bool");
+ cpl->parameter_get_default_double = dlsym(handle, "cpl_parameter_get_default_double");
+ cpl->parameter_get_default_int = dlsym(handle, "cpl_parameter_get_default_int");
+ cpl->parameter_get_default_string = dlsym(handle, "cpl_parameter_get_default_string");
+ cpl->parameter_get_enum_double = dlsym(handle, "cpl_parameter_get_enum_double");
+ cpl->parameter_get_enum_int = dlsym(handle, "cpl_parameter_get_enum_int");
+ cpl->parameter_get_enum_size = dlsym(handle, "cpl_parameter_get_enum_size");
+ cpl->parameter_get_enum_string = dlsym(handle, "cpl_parameter_get_enum_string");
+ cpl->parameter_get_help = dlsym(handle, "cpl_parameter_get_help");
+ cpl->parameter_get_name = dlsym(handle, "cpl_parameter_get_name");
+ cpl->parameter_get_range_max_double = dlsym(handle, "cpl_parameter_get_range_max_double");
+ cpl->parameter_get_range_max_int = dlsym(handle, "cpl_parameter_get_range_max_int");
+ cpl->parameter_get_range_min_double = dlsym(handle, "cpl_parameter_get_range_min_double");
+ cpl->parameter_get_range_min_int = dlsym(handle, "cpl_parameter_get_range_min_int");
+ cpl->parameter_get_type = dlsym(handle, "cpl_parameter_get_type");
+ cpl->parameter_set_bool = dlsym(handle, "cpl_parameter_set_bool");
+ cpl->parameter_set_double = dlsym(handle, "cpl_parameter_set_double");
+ cpl->parameter_set_int = dlsym(handle, "cpl_parameter_set_int");
+ cpl->parameter_set_string = dlsym(handle, "cpl_parameter_set_string");
+ cpl->parameterlist_find = dlsym(handle, "cpl_parameterlist_find");
+ cpl->parameterlist_get_first = dlsym(handle, "cpl_parameterlist_get_first");
+ cpl->parameterlist_get_next = dlsym(handle, "cpl_parameterlist_get_next");
+ cpl->parameterlist_get_size = dlsym(handle, "cpl_parameterlist_get_size");
+
+ cpl->recipeconfig_get_inputs = dlsym(handle, "cpl_recipeconfig_get_inputs");
+ cpl->recipeconfig_get_max_count = dlsym(handle, "cpl_recipeconfig_get_max_count");
+ cpl->recipeconfig_get_min_count = dlsym(handle, "cpl_recipeconfig_get_min_count");
+ cpl->recipeconfig_get_outputs = dlsym(handle, "cpl_recipeconfig_get_outputs");
+ cpl->recipeconfig_get_tags = dlsym(handle, "cpl_recipeconfig_get_tags");
+ cpl->version_get_version = dlsym(handle, "cpl_version_get_version");
+
+ error = dlerror();
+ if (error != NULL) {
+ dlclose(handle);
+ free(cpl);
+ return NULL;
+ }
+ cpl->get_recipeconfig = dlsym(handle, "muse_processing_get_recipeconfig");
+ dlerror();
+
+ cpl->init(CPL_INIT_DEFAULT);
+
+ typeof(cpl_version_get_major) *get_major = dlsym(handle,
+ "cpl_version_get_major");
+ typeof(cpl_version_get_minor) *get_minor = dlsym(handle,
+ "cpl_version_get_minor");
+ typeof(cpl_version_get_micro) *get_micro = dlsym(handle,
+ "cpl_version_get_micro");
+ cpl->TYPE_BOOL = CPL_TYPE_BOOL;
+ cpl->TYPE_INT = CPL_TYPE_INT;
+ cpl->TYPE_DOUBLE = CPL_TYPE_DOUBLE;
+ cpl->TYPE_STRING = CPL_TYPE_STRING;
+
+ cpl->version = CPL_VERSION(get_major(), get_minor(), get_micro());
+
+ cpl->is_supported = 0;
+ for (i = 0; supported_versions[i] != 0; i++) {
+ if (cpl->version == supported_versions[i]) {
+ cpl->is_supported = 1;
+ }
+ }
+
+ /* Between 5.3.1 and 6.0, the cpl_type enum changed.
+ http://upstream-tracker.org/compat_reports/cpl/5.3.1_to_6.0/abi_compat_report.html#Medium_Risk_Problems
+ for these changes; the numbers were taken from there. According to
+ upstream-tracker, this seems to be the only relevant API change between
+ 4.0.0 and 6.2.0.
+
+ Also the cpl_size is newly introduced (former it was int), in
+
+ cpl_frame *cpl_frameset_get_frame(cpl_frameset *self, cpl_size position);
+ cpl_size cpl_frameset_get_size(const cpl_frameset *self);
+ cpl_size cpl_parameterlist_get_size(const cpl_parameterlist *self);
+ cpl_size cpl_recipeconfig_get_min_count(const cpl_recipeconfig* self,
+ const char* tag, const char* input);
+ cpl_size cpl_recipeconfig_get_max_count(const cpl_recipeconfig* self,
+ const char* tag, const char* input);
+
+ Currently, we just ignore this :-)
+
+ */
+ if (cpl->version < CPL_VERSION(6,0,0)) {
+ cpl->TYPE_INT = (1 << 8);
+ cpl->TYPE_DOUBLE = (1 << 13);
+ }
+
+ libraries = realloc(libraries, sizeof(cpl_library_t *) * (i+2));
+ libraries[i] = cpl;
+ libraries[i+1] = NULL;
+ return cpl;
+}
+
diff --git a/cpl/CPL_library.h b/cpl/CPL_library.h
new file mode 100644
index 0000000..027a1db
--- /dev/null
+++ b/cpl/CPL_library.h
@@ -0,0 +1,125 @@
+
+#ifndef CPL_LIBRARY_H
+#define CPL_LIBRARY_H
+
+/* For the header, either the CPL one can be used, or the header that was
+ extracted from the 6.1.1 release. For API safety, it is better to include
+ the one provided with python-cpl. The other option is just for the adoption
+ to a new CPL version.
+ */
+#ifdef USE_INSTALLED_CPL_HEADER
+#include <cpl.h>
+#else
+#include "cpl_api.h"
+#endif
+
+#if CPL_VERSION_CODE < CPL_VERSION(6,0,0)
+#error CPL version too old. Minimum required version is 6.0.0.
+#endif
+#if CPL_VERSION_CODE > CPL_VERSION(6,2,0)
+#warning Newer CPL version: check API compability with 6.2.0 at http://upstream-tracker.org/versions/cpl.html
+#endif
+
+extern unsigned long supported_versions[];
+
+typedef struct {
+ unsigned long version;
+ int is_supported;
+
+ typeof(cpl_init) *init;
+ typeof(cpl_get_description) *get_description;
+ typeof(cpl_memory_dump) *memory_dump;
+ typeof(cpl_memory_is_empty) *memory_is_empty;
+ typeof(cpl_free) *free;
+
+ typeof(cpl_plugin_get_author) *plugin_get_author;
+ typeof(cpl_plugin_get_copyright) *plugin_get_copyright;
+ typeof(cpl_plugin_get_deinit) *plugin_get_deinit;
+ typeof(cpl_plugin_get_description) *plugin_get_description;
+ typeof(cpl_plugin_get_email) *plugin_get_email;
+ typeof(cpl_plugin_get_exec) *plugin_get_exec;
+ typeof(cpl_plugin_get_init) *plugin_get_init;
+ typeof(cpl_plugin_get_name) *plugin_get_name;
+ typeof(cpl_plugin_get_synopsis) *plugin_get_synopsis;
+ typeof(cpl_plugin_get_version) *plugin_get_version;
+ typeof(cpl_plugin_get_version_string) *plugin_get_version_string;
+ typeof(cpl_pluginlist_delete) *pluginlist_delete;
+ typeof(cpl_pluginlist_find) *pluginlist_find;
+ typeof(cpl_pluginlist_get_first) *pluginlist_get_first;
+ typeof(cpl_pluginlist_get_next) *pluginlist_get_next;
+ typeof(cpl_pluginlist_new) *pluginlist_new;
+
+ typeof(cpl_dfs_update_product_header) *dfs_update_product_header;
+
+ typeof(cpl_error_get_code) *error_get_code;
+ typeof(cpl_error_get_file) *error_get_file;
+ typeof(cpl_error_get_function) *error_get_function;
+ typeof(cpl_error_get_line) *error_get_line;
+ typeof(cpl_error_get_message) *error_get_message;
+ typeof(cpl_error_reset) *error_reset;
+ typeof(cpl_error_set_message_macro) *error_set_message_macro;
+ typeof(cpl_errorstate_dump) *errorstate_dump;
+ typeof(cpl_errorstate_get) *errorstate_get;
+
+ typeof(cpl_frame_get_filename) *frame_get_filename;
+ typeof(cpl_frame_get_group) *frame_get_group;
+ typeof(cpl_frame_get_tag) *frame_get_tag;
+ typeof(cpl_frame_new) *frame_new;
+ typeof(cpl_frame_set_filename) *frame_set_filename;
+ typeof(cpl_frame_set_tag) *frame_set_tag;
+ typeof(cpl_frameset_delete) *frameset_delete;
+ typeof(cpl_frameset_get_frame) *frameset_get_frame;
+ typeof(cpl_frameset_get_size) *frameset_get_size;
+ typeof(cpl_frameset_insert) *frameset_insert;
+ typeof(cpl_frameset_new) *frameset_new;
+
+ typeof(cpl_msg_error) *msg_error;
+ typeof(cpl_msg_set_level) *msg_set_level;
+ typeof(cpl_msg_set_log_level) *msg_set_log_level;
+ typeof(cpl_msg_set_log_name) *msg_set_log_name;
+ typeof(cpl_msg_stop_log) *msg_stop_log;
+
+ typeof(cpl_parameter_get_alias) *parameter_get_alias;
+ typeof(cpl_parameter_get_class) *parameter_get_class;
+ typeof(cpl_parameter_get_context) *parameter_get_context;
+ typeof(cpl_parameter_get_default_bool) *parameter_get_default_bool;
+ typeof(cpl_parameter_get_default_double) *parameter_get_default_double;
+ typeof(cpl_parameter_get_default_int) *parameter_get_default_int;
+ typeof(cpl_parameter_get_default_string) *parameter_get_default_string;
+ typeof(cpl_parameter_get_enum_double) *parameter_get_enum_double;
+ typeof(cpl_parameter_get_enum_int) *parameter_get_enum_int;
+ typeof(cpl_parameter_get_enum_size) *parameter_get_enum_size;
+ typeof(cpl_parameter_get_enum_string) *parameter_get_enum_string;
+ typeof(cpl_parameter_get_help) *parameter_get_help;
+ typeof(cpl_parameter_get_name) *parameter_get_name;
+ typeof(cpl_parameter_get_range_max_double) *parameter_get_range_max_double;
+ typeof(cpl_parameter_get_range_max_int) *parameter_get_range_max_int;
+ typeof(cpl_parameter_get_range_min_double) *parameter_get_range_min_double;
+ typeof(cpl_parameter_get_range_min_int) *parameter_get_range_min_int;
+ typeof(cpl_parameter_get_type) *parameter_get_type;
+ typeof(cpl_parameter_set_bool) *parameter_set_bool;
+ typeof(cpl_parameter_set_double) *parameter_set_double;
+ typeof(cpl_parameter_set_int) *parameter_set_int;
+ typeof(cpl_parameter_set_string) *parameter_set_string;
+ typeof(cpl_parameterlist_find) *parameterlist_find;
+ typeof(cpl_parameterlist_get_first) *parameterlist_get_first;
+ typeof(cpl_parameterlist_get_next) *parameterlist_get_next;
+ typeof(cpl_parameterlist_get_size) *parameterlist_get_size;
+
+ typeof(cpl_recipeconfig_get_inputs) *recipeconfig_get_inputs;
+ typeof(cpl_recipeconfig_get_max_count) *recipeconfig_get_max_count;
+ typeof(cpl_recipeconfig_get_min_count) *recipeconfig_get_min_count;
+ typeof(cpl_recipeconfig_get_outputs) *recipeconfig_get_outputs;
+ typeof(cpl_recipeconfig_get_tags) *recipeconfig_get_tags;
+ typeof(cpl_version_get_version) *version_get_version;
+ cpl_recipeconfig *(*get_recipeconfig)(cpl_recipe *);
+
+ cpl_type TYPE_BOOL;
+ cpl_type TYPE_INT;
+ cpl_type TYPE_DOUBLE;
+ cpl_type TYPE_STRING;
+} cpl_library_t;
+
+cpl_library_t *create_library(const char *fname);
+
+#endif /* CPL_LIBRARY_H */
diff --git a/cpl/CPL_recipe.c b/cpl/CPL_recipe.c
index 22ee312..6babb63 100644
--- a/cpl/CPL_recipe.c
+++ b/cpl/CPL_recipe.c
@@ -15,23 +15,7 @@
#define HAVE_MCHECK
#endif
-#include <cpl.h>
-
-#define CPL_version_doc \
- "Get the CPL version string."
-
-static PyObject *
-CPL_version(PyObject *self) {
- return Py_BuildValue("s", cpl_version_get_version());
-}
-
-#define CPL_description_doc \
- "Get the string of version numbers of CPL and its libraries."
-
-static PyObject *
-CPL_description(PyObject *self) {
- return Py_BuildValue("s", cpl_get_description(CPL_DESCRIPTION_DEFAULT));
-}
+#include "CPL_library.h"
#define CPL_list_doc \
"List all CPL recipe names contained in a shared library."
@@ -49,240 +33,62 @@ CPL_list(PyObject *self, PyObject *args) {
return Py_None;
}
- dlerror();
+ char *error =dlerror();
int (*cpl_plugin_get_info)(cpl_pluginlist *) = dlsym(handle,
"cpl_plugin_get_info");
- char *error = dlerror();
+ error = dlerror();
if (error != NULL) {
+ dlclose(handle);
Py_INCREF(Py_None);
return Py_None;
}
+
+ cpl_library_t *cpl = create_library(file);
+
PyObject *res = PyList_New(0);
Py_INCREF(res);
- cpl_pluginlist *list = cpl_pluginlist_new();
+ cpl_pluginlist *list = cpl->pluginlist_new();
(*cpl_plugin_get_info)(list);
cpl_plugin *plugin;
- for (plugin = cpl_pluginlist_get_first(list);
+ for (plugin = cpl->pluginlist_get_first(list);
plugin != NULL;
- plugin = cpl_pluginlist_get_next(list)) {
- cpl_error_reset();
- cpl_plugin_get_init(plugin)(plugin);
+ plugin = cpl->pluginlist_get_next(list)) {
+ cpl->error_reset();
+ cpl->plugin_get_init(plugin)(plugin);
PyList_Append(res, Py_BuildValue("sis",
- cpl_plugin_get_name(plugin),
- cpl_plugin_get_version(plugin),
- cpl_plugin_get_version_string(plugin)));
- cpl_plugin_get_deinit(plugin)(plugin);
+ cpl->plugin_get_name(plugin),
+ cpl->plugin_get_version(plugin),
+ cpl->plugin_get_version_string(plugin)));
+ cpl->plugin_get_deinit(plugin)(plugin);
}
- cpl_pluginlist_delete(list);
- cpl_error_reset();
+ cpl->pluginlist_delete(list);
+ cpl->error_reset();
dlclose(handle);
return res;
}
-#define CPL_set_msg_level_doc \
- "Set verbosity level of output to terminal."
-
-static PyObject *
-CPL_set_msg_level(PyObject *self, PyObject *args) {
- int level;
-
- if (!PyArg_ParseTuple(args, "i", &level))
- return NULL;
- cpl_msg_set_level(level);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_get_msg_level_doc \
- "Get current terminal verbosity level."
-
-static PyObject *
-CPL_get_msg_level(PyObject *self) {
- return Py_BuildValue("i", cpl_msg_get_level());
-}
-
-#define CPL_set_msg_time_doc \
- "Enable or disable the time tag in output messages."
-
-static PyObject *
-CPL_set_msg_time(PyObject *self, PyObject *args) {
- PyObject *enable;
- if (!PyArg_ParseTuple(args, "O", &enable))
- return NULL;
-
- if (PyObject_IsTrue(enable)) {
- cpl_msg_set_time_on();
- } else {
- cpl_msg_set_time_off();
- }
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_set_log_level_doc \
- "Set verbosity level of output to logfile."
-
-static PyObject *
-CPL_set_log_level(PyObject *self, PyObject *args) {
- int level;
-
- if (!PyArg_ParseTuple(args, "i", &level))
- return NULL;
- cpl_msg_set_log_level(level);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_get_log_level_doc \
- "Get current logfile verbosity level."
-
-static PyObject *
-CPL_get_log_level(PyObject *self) {
- return Py_BuildValue("i", cpl_msg_get_log_level());
-}
-
-#define CPL_set_log_file_doc \
- "Set the log file name."
-
-static PyObject *
-CPL_set_log_file(PyObject *self, PyObject *args) {
- const char *name;
-
- if (!PyArg_ParseTuple(args, "s", &name))
- return NULL;
- cpl_error_code r = cpl_msg_set_log_name(name);
- if (r != CPL_ERROR_NONE) {
- PyErr_SetString(PyExc_IOError, cpl_error_get_message());
- return NULL;
- }
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_get_log_file_doc \
- "Get the log file name."
-
-static PyObject *
-CPL_get_log_file(PyObject *self) {
- return Py_BuildValue("s", cpl_msg_get_log_name());
-}
-
-#define CPL_set_log_domain_doc \
- "Set the log domain name."
-
-static PyObject *
-CPL_set_log_domain(PyObject *self, PyObject *args) {
- const char *name;
-
- if (!PyArg_ParseTuple(args, "s", &name))
- return NULL;
- cpl_msg_set_domain(name);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_get_log_domain_doc \
- "Get the log domain name."
-
-static PyObject *
-CPL_get_log_domain(PyObject *self) {
- return Py_BuildValue("s", cpl_msg_get_domain());
-}
-
-#define CPL_log_doc \
- "Write a log message."
+#define CPL_supported_versions_doc \
+ "List all supported CPL versions."
static PyObject *
-CPL_log(PyObject *self, PyObject *args) {
- int level;
- const char *msg;
- const char *caller;
- if (!PyArg_ParseTuple(args, "iss", &level, &caller, &msg))
- return NULL;
- if (level < 0) level = 0;
- typedef void (*msg_func_t)(const char *, const char *,...);
- msg_func_t msg_func[]= {
- cpl_msg_debug,
- cpl_msg_info,
- cpl_msg_warning,
- cpl_msg_error
- };
- if (level <=3) {
- msg_func[level](caller, "%s", msg);
+CPL_supported_versions(PyObject *self, PyObject *args) {
+ PyObject *res = PyList_New(0);
+ Py_INCREF(res);
+ int i;
+ for (i = 0; supported_versions[i] != 0; i++) {
+ PyList_Append(res, Py_BuildValue(
+ "iii",
+ CPL_VERSION_MAJOR_CODE(supported_versions[i]),
+ CPL_VERSION_MINOR_CODE(supported_versions[i]),
+ CPL_VERSION_MICRO_CODE(supported_versions[i])));
}
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_log_indent_more_doc \
- "Increase the message indentation by one indentation step."
-
-static PyObject *
-CPL_log_indent_more(PyObject *self) {
- cpl_msg_indent_more();
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_log_indent_less_doc \
- "Decrease the message indentation by one indentation step."
-
-static PyObject *
-CPL_log_indent_less(PyObject *self) {
- cpl_msg_indent_less();
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_memory_dump_doc \
- "Display the memory status."
-
-static PyObject *
-CPL_memory_dump(PyObject *self) {
- cpl_memory_dump();
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-#define CPL_memory_is_empty_doc \
- "Tell if there is some memory allocated."
-
-static PyObject *
-CPL_memory_is_empty(PyObject *self) {
- return Py_BuildValue("i", cpl_memory_is_empty());
+ return res;
}
static PyMethodDef CPL_methods[] = {
- {"version", (PyCFunction)CPL_version, METH_NOARGS, CPL_version_doc},
- {"description", (PyCFunction)CPL_description, METH_NOARGS, CPL_version_doc},
{"list", CPL_list, METH_VARARGS, CPL_list_doc},
- {"set_msg_level", CPL_set_msg_level, METH_VARARGS, CPL_set_msg_level_doc},
- {"get_msg_level", (PyCFunction)CPL_get_msg_level, METH_NOARGS,
- CPL_get_msg_level_doc},
- {"set_msg_time", CPL_set_msg_time, METH_VARARGS, CPL_set_msg_time_doc },
- {"set_log_level", CPL_set_log_level, METH_VARARGS, CPL_set_log_level_doc},
- {"get_log_level", (PyCFunction)CPL_get_log_level, METH_NOARGS,
- CPL_get_log_level_doc},
- {"set_log_file", CPL_set_log_file, METH_VARARGS, CPL_set_log_file_doc},
- {"get_log_file", (PyCFunction)CPL_get_log_file, METH_NOARGS,
- CPL_get_log_file_doc },
- {"set_log_domain", CPL_set_log_domain, METH_VARARGS,
- CPL_set_log_domain_doc},
- {"get_log_domain", (PyCFunction)CPL_get_log_domain, METH_NOARGS,
- CPL_get_log_domain_doc },
- {"log", CPL_log, METH_VARARGS, CPL_log_doc},
- {"log_indent_more", (PyCFunction)CPL_log_indent_more, METH_NOARGS,
- CPL_log_indent_more_doc},
- {"log_indent_less", (PyCFunction)CPL_log_indent_less, METH_NOARGS,
- CPL_log_indent_less_doc},
- {"memory_dump", (PyCFunction)CPL_memory_dump, METH_NOARGS,
- CPL_memory_dump_doc},
- {"memory_is_empty", (PyCFunction)CPL_memory_is_empty, METH_NOARGS,
- CPL_memory_is_empty_doc},
+ {"cpl_versions", CPL_supported_versions, METH_NOARGS,
+ CPL_supported_versions_doc},
{NULL, NULL, 0, NULL} /* Sentinel */
};
@@ -292,15 +98,16 @@ typedef struct {
cpl_pluginlist *pluginlist;
void *handle;
cpl_recipeconfig *recipeconfig;
+ cpl_library_t *cpl;
} CPL_recipe;
static void
CPL_recipe_dealloc(CPL_recipe* self) {
if (self->plugin != NULL) {
- cpl_plugin_get_deinit(self->plugin)(self->plugin);
+ self->cpl->plugin_get_deinit(self->plugin)(self->plugin);
}
if (self->pluginlist != NULL) {
- cpl_pluginlist_delete(self->pluginlist);
+ self->cpl->pluginlist_delete(self->pluginlist);
}
if (self->handle != NULL) {
dlclose(self->handle);
@@ -316,6 +123,7 @@ CPL_recipe_new(PyTypeObject *type, PyObject *args, PyObject *kwds) {
self->pluginlist = NULL;
self->handle = NULL;
self->recipeconfig = NULL;
+ self->cpl = NULL;
}
return (PyObject *)self;
}
@@ -346,106 +154,112 @@ CPL_recipe_init(CPL_recipe *self, PyObject *args, PyObject *kwds) {
PyErr_SetString(PyExc_IOError, error);
return -1;
}
- cpl_error_reset();
- self->pluginlist = cpl_pluginlist_new();
+
+ self->cpl = create_library(file);
+ self->cpl->error_reset();
+ self->pluginlist = self->cpl->pluginlist_new();
(*cpl_plugin_get_info)(self->pluginlist);
- self->plugin = cpl_pluginlist_find(self->pluginlist, recipe);
+ self->plugin = self->cpl->pluginlist_find(self->pluginlist, recipe);
if (self->plugin == NULL) {
PyErr_SetString(PyExc_IOError, "cannot find recipe in shared library");
return -1;
} else {
- cpl_plugin_get_init(self->plugin)(self->plugin);
+ self->cpl->plugin_get_init(self->plugin)(self->plugin);
}
- cpl_recipeconfig *(*get_recipeconfig)(cpl_recipe *)
- = dlsym(self->handle, "muse_processing_get_recipeconfig");
- if (dlerror() == NULL && get_recipeconfig != NULL) {
- self->recipeconfig = get_recipeconfig((cpl_recipe *)self->plugin);
+ if (self->cpl->get_recipeconfig != NULL) {
+ self->recipeconfig = self->cpl->get_recipeconfig((cpl_recipe *)self->plugin);
} else {
self->recipeconfig = NULL;
}
return 0;
}
+#define CPL_is_supported_doc \
+ "Check whether the CPL version is supported by python-cpl."
+
+static PyObject *
+CPL_is_supported(CPL_recipe *self) {
+ return (self->cpl->is_supported)?Py_True:Py_False;
+}
+
+#define CPL_version_doc \
+ "Get the CPL version string."
+
+static PyObject *
+CPL_version(CPL_recipe *self) {
+ return Py_BuildValue("s", self->cpl->version_get_version());
+}
+
+#define CPL_description_doc \
+ "Get the string of version numbers of CPL and its libraries."
+
+static PyObject *
+CPL_description(CPL_recipe *self) {
+ return Py_BuildValue("s", self->cpl->get_description(CPL_DESCRIPTION_DEFAULT));
+}
+
static PyObject *
-getParameter(cpl_parameter *param) {
- cpl_type type = cpl_parameter_get_type(param);
- cpl_parameter_class class = cpl_parameter_get_class(param);
- const char *name = cpl_parameter_get_alias(param,
+getParameter(CPL_recipe *self, cpl_parameter *param) {
+ cpl_type type = self->cpl->parameter_get_type(param);
+ cpl_parameter_class class = self->cpl->parameter_get_class(param);
+ const char *name = self->cpl->parameter_get_alias(param,
CPL_PARAMETER_MODE_CLI);
- const char *fullname = cpl_parameter_get_name(param);
- const char *context = cpl_parameter_get_context(param);
- const char *help = cpl_parameter_get_help(param);
+ const char *fullname = self->cpl->parameter_get_name(param);
+ const char *context = self->cpl->parameter_get_context(param);
+ const char *help = self->cpl->parameter_get_help(param);
PyObject *range = Py_None;
if (class == CPL_PARAMETER_CLASS_RANGE) {
- switch (type) {
- case CPL_TYPE_INT:
- range = Py_BuildValue("ii",
- cpl_parameter_get_range_min_int(param),
- cpl_parameter_get_range_max_int(param));
- break;
- case CPL_TYPE_DOUBLE:
- range = Py_BuildValue("dd",
- cpl_parameter_get_range_min_double(param),
- cpl_parameter_get_range_max_double(param));
- break;
- default:
- break;
+ if (type == self->cpl->TYPE_INT) {
+ range = Py_BuildValue("ii",
+ self->cpl->parameter_get_range_min_int(param),
+ self->cpl->parameter_get_range_max_int(param));
+ } else if (type == self->cpl->TYPE_DOUBLE) {
+ range = Py_BuildValue("dd",
+ self->cpl->parameter_get_range_min_double(param),
+ self->cpl->parameter_get_range_max_double(param));
}
}
Py_INCREF(range);
PyObject *sequence = Py_None;
if (class == CPL_PARAMETER_CLASS_ENUM) {
sequence = PyList_New(0);
- int n_enum = cpl_parameter_get_enum_size(param);
+ int n_enum = self->cpl->parameter_get_enum_size(param);
int i;
for (i = 0; i < n_enum; i++) {
- switch (type) {
- case CPL_TYPE_INT:
- PyList_Append(
- sequence,
- Py_BuildValue("i",
- cpl_parameter_get_enum_int(param, i)));
- break;
- case CPL_TYPE_DOUBLE:
- PyList_Append(
- sequence,
- Py_BuildValue("d",
- cpl_parameter_get_enum_double(param, i)));
- break;
- case CPL_TYPE_STRING:
- PyList_Append(
- sequence,
- Py_BuildValue("s",
- cpl_parameter_get_enum_string(param, i)));
- break;
- default:
- break;
+ if (type == self->cpl->TYPE_INT) {
+ PyList_Append(
+ sequence,
+ Py_BuildValue("i",
+ self->cpl->parameter_get_enum_int(param, i)));
+ } else if (type == self->cpl->TYPE_DOUBLE) {
+ PyList_Append(
+ sequence,
+ Py_BuildValue("d",
+ self->cpl->parameter_get_enum_double(param, i)));
+ } else if (type == self->cpl->TYPE_STRING) {
+ PyList_Append(
+ sequence,
+ Py_BuildValue("s",
+ self->cpl->parameter_get_enum_string(param, i)));
}
}
}
Py_INCREF(sequence);
PyObject *deflt = Py_None;
PyObject *ptype = Py_None;
- switch (type) {
- case CPL_TYPE_BOOL:
- ptype = (PyObject *)&PyBool_Type;
- deflt = (cpl_parameter_get_default_bool(param))?Py_True:Py_False;
- break;
- case CPL_TYPE_INT:
- ptype = (PyObject *)&PyInt_Type;
- deflt = Py_BuildValue("i", cpl_parameter_get_default_int(param));
- break;
- case CPL_TYPE_DOUBLE:
- ptype = (PyObject *)&PyFloat_Type;
- deflt = Py_BuildValue("d", cpl_parameter_get_default_double(param));
- break;
- case CPL_TYPE_STRING:
- ptype = (PyObject *)&PyString_Type;
- deflt = Py_BuildValue("s", cpl_parameter_get_default_string(param));
- break;
- default:
- break;
+ if (type == self->cpl->TYPE_BOOL) {
+ ptype = (PyObject *)&PyBool_Type;
+ deflt = (self->cpl->parameter_get_default_bool(param))?Py_True:Py_False;
+ } else if (type == self->cpl->TYPE_INT) {
+ ptype = (PyObject *)&PyInt_Type;
+ deflt = Py_BuildValue("i", self->cpl->parameter_get_default_int(param));
+ } else if (type == self->cpl->TYPE_DOUBLE) {
+ ptype = (PyObject *)&PyFloat_Type;
+ deflt = Py_BuildValue("d", self->cpl->parameter_get_default_double(param));
+ } else if (type == self->cpl->TYPE_STRING) {
+ ptype = (PyObject *)&PyString_Type;
+ deflt = Py_BuildValue("s", self->cpl->parameter_get_default_string(param));
}
Py_INCREF(deflt);
Py_INCREF(ptype);
@@ -476,12 +290,12 @@ CPL_recipe_get_params(CPL_recipe *self) {
}
cpl_parameterlist *pars = ((cpl_recipe *)self->plugin)->parameters;
PyObject *res = PyList_New(0);
- if (pars && cpl_parameterlist_get_size(pars)) {
+ if (pars && self->cpl->parameterlist_get_size(pars)) {
cpl_parameter *param;
- for (param = cpl_parameterlist_get_first(pars);
+ for (param = self->cpl->parameterlist_get_first(pars);
param != NULL;
- param = cpl_parameterlist_get_next(pars)) {
- PyList_Append(res, getParameter(param));
+ param = self->cpl->parameterlist_get_next(pars)) {
+ PyList_Append(res, getParameter(self, param));
}
}
Py_INCREF(res);
@@ -500,8 +314,8 @@ CPL_recipe_get_author(CPL_recipe *self) {
return NULL;
}
return Py_BuildValue("ss",
- cpl_plugin_get_author(self->plugin),
- cpl_plugin_get_email(self->plugin));
+ self->cpl->plugin_get_author(self->plugin),
+ self->cpl->plugin_get_email(self->plugin));
}
#define CPL_recipe_get_description_doc \
@@ -516,8 +330,8 @@ CPL_recipe_get_description(CPL_recipe *self) {
return NULL;
}
return Py_BuildValue("ss",
- cpl_plugin_get_synopsis(self->plugin),
- cpl_plugin_get_description(self->plugin));
+ self->cpl->plugin_get_synopsis(self->plugin),
+ self->cpl->plugin_get_description(self->plugin));
}
#define CPL_recipe_get_version_doc \
@@ -532,8 +346,8 @@ CPL_recipe_get_version(CPL_recipe *self) {
return NULL;
}
return Py_BuildValue("is",
- cpl_plugin_get_version(self->plugin),
- cpl_plugin_get_version_string(self->plugin));
+ self->cpl->plugin_get_version(self->plugin),
+ self->cpl->plugin_get_version_string(self->plugin));
}
#define CPL_recipe_get_copyright_doc \
@@ -546,7 +360,7 @@ CPL_recipe_get_copyright(CPL_recipe *self) {
return NULL;
}
return Py_BuildValue("s",
- cpl_plugin_get_copyright(self->plugin));
+ self->cpl->plugin_get_copyright(self->plugin));
}
#define CPL_recipe_get_frameconfig_doc \
@@ -571,63 +385,63 @@ CPL_recipe_get_frameconfig(CPL_recipe *self) {
return Py_None;
}
PyObject *res = PyList_New(0);
- char **tags = cpl_recipeconfig_get_tags(self->recipeconfig);
+ char **tags = self->cpl->recipeconfig_get_tags(self->recipeconfig);
int i_tag;
for (i_tag = 0; tags[i_tag] != NULL; i_tag++) {
- int min = cpl_recipeconfig_get_min_count(self->recipeconfig,
+ int min = self->cpl->recipeconfig_get_min_count(self->recipeconfig,
tags[i_tag], tags[i_tag]);
- int max = cpl_recipeconfig_get_max_count(self->recipeconfig,
+ int max = self->cpl->recipeconfig_get_max_count(self->recipeconfig,
tags[i_tag], tags[i_tag]);
PyObject *raw = Py_BuildValue("sii", tags[i_tag], min, max);
PyObject *calib = PyList_New(0);
- char **inputs = cpl_recipeconfig_get_inputs(self->recipeconfig,
+ char **inputs = self->cpl->recipeconfig_get_inputs(self->recipeconfig,
tags[i_tag]);
int i_input;
for (i_input = 0; inputs[i_input] != NULL; i_input++) {
- int min = cpl_recipeconfig_get_min_count(self->recipeconfig,
+ int min = self->cpl->recipeconfig_get_min_count(self->recipeconfig,
tags[i_tag],
inputs[i_input]);
- int max = cpl_recipeconfig_get_max_count(self->recipeconfig,
+ int max = self->cpl->recipeconfig_get_max_count(self->recipeconfig,
tags[i_tag],
inputs[i_input]);
PyList_Append(calib, Py_BuildValue("sii", inputs[i_input],
min, max));
- cpl_free(inputs[i_input]);
+ self->cpl->free(inputs[i_input]);
}
- cpl_free(inputs);
+ self->cpl->free(inputs);
PyObject *output = PyList_New(0);
- char **outputs = cpl_recipeconfig_get_outputs(self->recipeconfig,
+ char **outputs = self->cpl->recipeconfig_get_outputs(self->recipeconfig,
tags[i_tag]);
int i_output;
for (i_output = 0; outputs[i_output] != NULL; i_output++) {
PyList_Append(output, Py_BuildValue("s", outputs[i_output]));
- cpl_free(outputs[i_output]);
+ self->cpl->free(outputs[i_output]);
}
- cpl_free(outputs);
+ self->cpl->free(outputs);
PyList_Append(res, Py_BuildValue("OOO", raw, calib, output));
- cpl_free(tags[i_tag]);
+ self->cpl->free(tags[i_tag]);
}
- cpl_free(tags);
+ self->cpl->free(tags);
return res;
}
static cpl_frameset *
-get_frames(PyObject *framelist) {
- cpl_frameset *frames = cpl_frameset_new();
+get_frames(CPL_recipe *self, PyObject *framelist) {
+ cpl_frameset *frames = self->cpl->frameset_new();
PyObject *iter = PyObject_GetIter(framelist);
PyObject *item;
while ((item = PyIter_Next(iter))) {
const char *tag;
const char* file;
PyArg_ParseTuple(item, "ss", &tag, &file);
- cpl_frame *frame = cpl_frame_new();
- cpl_frame_set_filename(frame, file);
- cpl_frame_set_tag(frame, tag);
- cpl_frameset_insert(frames, frame);
+ cpl_frame *frame = self->cpl->frame_new();
+ self->cpl->frame_set_filename(frame, file);
+ self->cpl->frame_set_tag(frame, tag);
+ self->cpl->frameset_insert(frames, frame);
Py_DECREF(item);
}
Py_DECREF(iter);
@@ -635,74 +449,81 @@ get_frames(PyObject *framelist) {
}
static void
-clear_parameters(cpl_parameterlist *parameters) {
- cpl_parameter *par = cpl_parameterlist_get_first(parameters);
+clear_parameters(CPL_recipe *self, cpl_parameterlist *parameters) {
+ cpl_parameter *par = self->cpl->parameterlist_get_first(parameters);
while (par != NULL) {
- cpl_type type = cpl_parameter_get_type(par);
- switch(type) {
- case CPL_TYPE_STRING: {
- const char *default_value = cpl_parameter_get_default_string(par);
- if (default_value == NULL) {
- default_value = "";
- }
- cpl_parameter_set_string(par, default_value);
+ cpl_type type = self->cpl->parameter_get_type(par);
+ if (type == self->cpl->TYPE_STRING) {
+ const char *default_value = self->cpl->parameter_get_default_string(par);
+ if (default_value == NULL) {
+ default_value = "";
}
- break;
- case CPL_TYPE_INT:
- cpl_parameter_set_int(par,
- cpl_parameter_get_default_int(par));
- break;
- case CPL_TYPE_DOUBLE:
- cpl_parameter_set_double(par,
- cpl_parameter_get_default_double(par));
- break;
- case CPL_TYPE_BOOL:
- cpl_parameter_set_bool(par,
- cpl_parameter_get_default_bool(par));
- break;
- default:
- break;
+ self->cpl->parameter_set_string(par, default_value);
+ } else if (type == self->cpl->TYPE_INT) {
+ self->cpl->parameter_set_int(par,
+ self->cpl->parameter_get_default_int(par));
+ } else if (type == self->cpl->TYPE_DOUBLE) {
+ self->cpl->parameter_set_double(par,
+ self->cpl->parameter_get_default_double(par));
+ } else if (type == self->cpl->TYPE_BOOL) {
+ self->cpl->parameter_set_bool(par,
+ self->cpl->parameter_get_default_bool(par));
}
- par = cpl_parameterlist_get_next(parameters);
+ par = self->cpl->parameterlist_get_next(parameters);
}
}
static void
-set_parameters(cpl_parameterlist *parameters, PyObject *parlist) {
+set_parameters(CPL_recipe *self, cpl_parameterlist *parameters, PyObject *parlist) {
PyObject *iter = PyObject_GetIter(parlist);
PyObject *item;
while ((item = PyIter_Next(iter))) {
const char *name;
PyObject *value;
PyArg_ParseTuple(item, "sO", &name, &value);
- cpl_parameter *par = cpl_parameterlist_find(parameters, name);
+ cpl_parameter *par = self->cpl->parameterlist_find(parameters, name);
if (par == NULL) {
continue;
}
- cpl_type type = cpl_parameter_get_type(par);
- switch(type) {
- case CPL_TYPE_STRING:
- if (PyString_Check(value)) {
- cpl_parameter_set_string(par, PyString_AsString(value));
- }
- break;
- case CPL_TYPE_INT:
- if (PyInt_Check(value)) {
- cpl_parameter_set_int(par, PyInt_AsLong(value));
- }
- break;
- case CPL_TYPE_DOUBLE:
- if (PyFloat_Check(value)) {
- cpl_parameter_set_double(par, PyFloat_AsDouble(value));
- }
- break;
- case CPL_TYPE_BOOL:
- cpl_parameter_set_bool(par, PyObject_IsTrue(value));
- break;
- default:
- break;
+ cpl_type type = self->cpl->parameter_get_type(par);
+ if (type == self->cpl->TYPE_STRING) {
+ if (PyString_Check(value)) {
+ self->cpl->parameter_set_string(par, PyString_AsString(value));
+ }
+ } else if (type == self->cpl->TYPE_INT) {
+ if (PyInt_Check(value)) {
+ self->cpl->parameter_set_int(par, PyInt_AsLong(value));
+ }
+ } else if (type == self->cpl->TYPE_DOUBLE) {
+ if (PyFloat_Check(value)) {
+ self->cpl->parameter_set_double(par, PyFloat_AsDouble(value));
+ }
+ } else if (type == self->cpl->TYPE_BOOL) {
+ self->cpl->parameter_set_bool(par, PyObject_IsTrue(value));
+ }
+ Py_DECREF(item);
+ }
+ Py_DECREF(iter);
+}
+
+static void
+set_environment(PyObject *runenv) {
+ PyObject *iter = PyObject_GetIter(runenv);
+ PyObject *item;
+ while ((item = PyIter_Next(iter))) {
+ const char *name;
+ PyObject *value;
+ PyArg_ParseTuple(item, "sO", &name, &value);
+ if ((name == NULL) || (value == NULL)) {
+ continue;
+ }
+ if (PyString_Check(value)) {
+ setenv(name, PyString_AsString(value), 1);
+ }
+ if (value == Py_None) {
+ unsetenv(name);
}
Py_DECREF(item);
}
@@ -750,58 +571,60 @@ exec_build_retval(void *ptr) {
}
static void *sbuffer_append_string(void *buf, const char *str) {
- buf = cpl_realloc(buf, ((long *)buf)[0] + strlen(str) + 1);
+ buf = realloc(buf, ((long *)buf)[0] + strlen(str) + 1);
strcpy(buf + *((long *)buf), str);
*((long *)buf) += strlen(str) + 1;
return buf;
}
static void *sbuffer_append_bytes(void *buf, const void *src, size_t nbytes) {
- buf = cpl_realloc(buf, ((long *)buf)[0] + nbytes);
+ buf = realloc(buf, ((long *)buf)[0] + nbytes);
memcpy(buf + *((long *)buf), src, nbytes);
*((long *)buf) += nbytes;
return buf;
}
static void *sbuffer_append_long(void *buf, long val) {
- buf = cpl_realloc(buf, *((long *)buf) + sizeof(long));
+ buf = realloc(buf, *((long *)buf) + sizeof(long));
*((long *)(buf + ((long *)buf)[0])) = val;
*((long *)buf) += sizeof(long);
return buf;
}
static void *serialized_error_ptr = NULL;
+static cpl_library_t *serialized_cpl = NULL;
static void
exec_serialize_one_error(unsigned self, unsigned first, unsigned last) {
if (serialized_error_ptr == NULL) {
- serialized_error_ptr = cpl_malloc(sizeof(long));
+ serialized_error_ptr = malloc(sizeof(long));
((long *)serialized_error_ptr)[0] = sizeof(long);
serialized_error_ptr = sbuffer_append_long(serialized_error_ptr, 0);
}
- if (cpl_error_get_code() == CPL_ERROR_NONE) {
+ if (serialized_cpl->error_get_code() == CPL_ERROR_NONE) {
return;
}
((long *)serialized_error_ptr)[1]++; // number of errors
serialized_error_ptr = sbuffer_append_long(serialized_error_ptr,
- cpl_error_get_code());
+ serialized_cpl->error_get_code());
serialized_error_ptr = sbuffer_append_long(serialized_error_ptr,
- cpl_error_get_line());
+ serialized_cpl->error_get_line());
serialized_error_ptr = sbuffer_append_string(serialized_error_ptr,
- cpl_error_get_message());
+ serialized_cpl->error_get_message());
serialized_error_ptr = sbuffer_append_string(serialized_error_ptr,
- cpl_error_get_file());
+ serialized_cpl->error_get_file());
serialized_error_ptr = sbuffer_append_string(serialized_error_ptr,
- cpl_error_get_function());
+ serialized_cpl->error_get_function());
}
static void *
-exec_serialize_retval(cpl_frameset *frames, cpl_errorstate prestate, int retval,
+exec_serialize_retval(CPL_recipe *self, cpl_frameset *frames,
+ cpl_errorstate prestate, int retval,
const struct tms *tms_clock) {
- int n_frames = cpl_frameset_get_size(frames);
+ int n_frames = self->cpl->frameset_get_size(frames);
int i_frame;
- void *ptr = cpl_malloc(sizeof(long));
+ void *ptr = malloc(sizeof(long));
((long *)ptr)[0] = sizeof(long);
ptr = sbuffer_append_long(ptr, retval);
ptr = sbuffer_append_long(ptr, 1000000L *
@@ -810,21 +633,23 @@ exec_serialize_retval(cpl_frameset *frames, cpl_errorstate prestate, int retval,
ptr = sbuffer_append_long(ptr, 1000000L *
(tms_clock->tms_stime + tms_clock->tms_cstime)
/ sysconf(_SC_CLK_TCK));
- ptr = sbuffer_append_long(ptr, cpl_memory_is_empty());
+ ptr = sbuffer_append_long(ptr, self->cpl->memory_is_empty());
- cpl_errorstate_dump(prestate, CPL_FALSE, exec_serialize_one_error);
+ serialized_cpl = self->cpl;
+ self->cpl->errorstate_dump(prestate, CPL_FALSE, exec_serialize_one_error);
ptr = sbuffer_append_bytes(ptr, serialized_error_ptr + sizeof(long),
((long *)serialized_error_ptr)[0] - sizeof(long));
- cpl_free(serialized_error_ptr);
+ free(serialized_error_ptr);
serialized_error_ptr = NULL;
+ serialized_cpl = NULL;
for (i_frame = 0; i_frame < n_frames; i_frame++) {
- cpl_frame *f = cpl_frameset_get_frame(frames, i_frame);
- if (cpl_frame_get_group(f) != CPL_FRAME_GROUP_PRODUCT) {
+ cpl_frame *f = self->cpl->frameset_get_frame(frames, i_frame);
+ if (self->cpl->frame_get_group(f) != CPL_FRAME_GROUP_PRODUCT) {
continue;
}
- ptr = sbuffer_append_string(ptr, cpl_frame_get_tag(f));
- ptr = sbuffer_append_string(ptr, cpl_frame_get_filename(f));
+ ptr = sbuffer_append_string(ptr, self->cpl->frame_get_tag(f));
+ ptr = sbuffer_append_string(ptr, self->cpl->frame_get_filename(f));
}
return ptr;
}
@@ -878,7 +703,7 @@ static void setup_tracing(CPL_recipe *self) {
#endif
#ifdef PR_SET_NAME
/* Set the process name for the calling process */
- prctl(PR_SET_NAME, cpl_plugin_get_name(self->plugin), 0, 0, 0);
+ prctl(PR_SET_NAME, self->cpl->plugin_get_name(self->plugin), 0, 0, 0);
#endif
#endif
#ifdef HAVE_MCHECK
@@ -908,12 +733,13 @@ static PyObject *
CPL_recipe_exec(CPL_recipe *self, PyObject *args) {
PyObject *parlist;
PyObject *soflist;
+ PyObject *runenv;
const char *dirname;
const char *logfile;
int loglevel;
int memory_dump;
- if (!PyArg_ParseTuple(args, "sOOsii", &dirname, &parlist, &soflist,
- &logfile, &loglevel, &memory_dump))
+ if (!PyArg_ParseTuple(args, "sOOOsii", &dirname, &parlist, &soflist,
+ &runenv, &logfile, &loglevel, &memory_dump))
return NULL;
if (!PySequence_Check(parlist)) {
PyErr_SetString(PyExc_TypeError, "Second parameter not a list");
@@ -923,18 +749,22 @@ CPL_recipe_exec(CPL_recipe *self, PyObject *args) {
PyErr_SetString(PyExc_TypeError, "Third parameter not a list");
return NULL;
}
+ if (!PySequence_Check(runenv)) {
+ PyErr_SetString(PyExc_TypeError, "Fourth parameter not a list");
+ return NULL;
+ }
if (self->plugin == NULL) {
PyErr_SetString(PyExc_IOError, "NULL recipe");
return NULL;
}
- cpl_error_reset();
+ self->cpl->error_reset();
cpl_recipe *recipe = (cpl_recipe *)self->plugin;
- cpl_frameset_delete(recipe->frames);
- recipe->frames = get_frames(soflist);
- clear_parameters(recipe->parameters);
- set_parameters(recipe->parameters, parlist);
- if (cpl_error_get_code() != CPL_ERROR_NONE) {
+ self->cpl->frameset_delete(recipe->frames);
+ recipe->frames = get_frames(self, soflist);
+ clear_parameters(self, recipe->parameters);
+ set_parameters(self, recipe->parameters, parlist);
+ if (self->cpl->error_get_code() != CPL_ERROR_NONE) {
PyErr_SetString(PyExc_IOError, "CPL error on inititalization");
return NULL;
}
@@ -953,33 +783,35 @@ CPL_recipe_exec(CPL_recipe *self, PyObject *args) {
close(fd[0]);
int retval;
struct tms clock_end;
- cpl_msg_set_log_name(logfile);
- cpl_msg_set_log_level(loglevel);
- cpl_errorstate prestate = cpl_errorstate_get();
+ set_environment(runenv);
+ self->cpl->msg_set_log_name(logfile);
+ self->cpl->msg_set_log_level(loglevel);
+ self->cpl->msg_set_level(CPL_MSG_OFF);
+ cpl_errorstate prestate = self->cpl->errorstate_get();
if (chdir(dirname) == 0) {
struct tms clock_start;
times(&clock_start);
setup_tracing(self);
- retval = cpl_plugin_get_exec(self->plugin)(self->plugin);
- int reto = cpl_dfs_update_product_header(recipe->frames);
+ retval = self->cpl->plugin_get_exec(self->plugin)(self->plugin);
+ int reto = self->cpl->dfs_update_product_header(recipe->frames);
if (reto != CPL_ERROR_NONE) {
- cpl_msg_error (__func__, "could not update the product header");
+ self->cpl->msg_error (__func__, "could not update the product header");
}
times(&clock_end);
clock_end.tms_utime -= clock_start.tms_utime;
clock_end.tms_stime -= clock_start.tms_stime;
clock_end.tms_cutime -= clock_start.tms_cutime;
clock_end.tms_cstime -= clock_start.tms_cstime;
- cpl_msg_stop_log();
+ self->cpl->msg_stop_log();
} else {
retval = CPL_ERROR_FILE_NOT_CREATED;
- cpl_error_set(__func__, retval);
+ self->cpl->error_set_message_macro(__func__, retval, __FILE__, __LINE__, " ");
}
if ((memory_dump > 1)
- || ((memory_dump > 0) && (!cpl_memory_is_empty()))) {
- cpl_memory_dump();
+ || ((memory_dump > 0) && (!self->cpl->memory_is_empty()))) {
+ self->cpl->memory_dump();
}
- void *ptr = exec_serialize_retval(recipe->frames, prestate,
+ void *ptr = exec_serialize_retval(self, recipe->frames, prestate,
retval, &clock_end);
long n_bytes = write(fd[1], ptr, ((long *)ptr)[0]);
close(fd[1]);
@@ -988,11 +820,11 @@ CPL_recipe_exec(CPL_recipe *self, PyObject *args) {
close(fd[1]);
long nbytes;
- void *ptr = cpl_malloc(2 * sizeof(long));
+ void *ptr = malloc(2 * sizeof(long));
Py_BEGIN_ALLOW_THREADS
nbytes = read(fd[0], ptr, 2 * sizeof(long));
if (nbytes == 2 * sizeof(long)) {
- ptr = cpl_realloc(ptr, ((long *)ptr)[0]);
+ ptr = realloc(ptr, ((long *)ptr)[0]);
nbytes += read(fd[0], ptr + 2 * sizeof(long),
((long *)ptr)[0] - 2 * sizeof(long));
} else { // broken pipe while reading first two bytes
@@ -1006,7 +838,7 @@ Py_END_ALLOW_THREADS
return NULL;
}
PyObject *retval = exec_build_retval(ptr);
- cpl_free(ptr);
+ free(ptr);
return retval;
}
@@ -1025,6 +857,10 @@ static PyMethodDef CPL_recipe_methods[] = {
CPL_recipe_get_frameconfig_doc},
{"run", (PyCFunction)CPL_recipe_exec, METH_VARARGS,
CPL_recipe_exec_doc},
+ {"cpl_is_supported", (PyCFunction)CPL_is_supported, METH_NOARGS,
+ CPL_is_supported_doc},
+ {"cpl_version", (PyCFunction)CPL_version, METH_NOARGS, CPL_version_doc},
+ {"cpl_description", (PyCFunction)CPL_description, METH_NOARGS, CPL_version_doc},
{NULL, NULL, 0, NULL} /* Sentinel */
};
@@ -1077,8 +913,6 @@ static PyTypeObject CPL_recipeType = {
PyMODINIT_FUNC
initCPL_recipe(void)
{
- cpl_init(CPL_INIT_DEFAULT);
-
CPL_recipeType.tp_new = PyType_GenericNew;
if (PyType_Ready(&CPL_recipeType) < 0)
return;
diff --git a/cpl/__init__.py b/cpl/__init__.py
index b31ad61..70bce66 100644
--- a/cpl/__init__.py
+++ b/cpl/__init__.py
@@ -7,15 +7,12 @@ from version import email as __email__
from version import license_ as __license__
from version import doc as __doc__
-from recipes import Recipe
-from parameters import Parameter
+from recipe import Recipe
+from param import Parameter
from frames import FrameConfig
from result import Result, CplError, RecipeCrash
-from log import msg, lib_version, lib_description
import dfs
import esorex
-msg.domain = os.path.basename(sys.argv[0])
-msg.level = msg.OFF
-
Recipe.dir = '.'
+cpl_versions = [ '%i.%i.%i' % ver for ver in CPL_recipe.cpl_versions() ]
diff --git a/cpl/cpl_api.h b/cpl/cpl_api.h
new file mode 100644
index 0000000..db46f69
--- /dev/null
+++ b/cpl/cpl_api.h
@@ -0,0 +1,189 @@
+/*
+
+ This header file is compiled from the original CPL header files to contain
+ just the functions and macros that we need in the framework.
+
+ Since it is mainly copied and pasted, here is the original license
+ statement from /usr/include/cpl.h:
+
+ * $Id: cpl.h,v 1.31 2009/12/02 10:29:45 lbilbao Exp $
+ *
+ * This file is part of the ESO Common Pipeline Library
+ * Copyright (C) 2001-2008 European Southern Observatory
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+ */
+#ifndef CPL_API_H
+#define CPL_API_H
+
+#define CPL_VERSION(major, minor, micro) \
+ (((major) * 65536) + ((minor) * 256) + (micro))
+
+#define CPL_VERSION_MAJOR_CODE(code) (((code) >> 16) & 0xff)
+#define CPL_VERSION_MINOR_CODE(code) (((code) >> 8) & 0xff)
+#define CPL_VERSION_MICRO_CODE(code) ((code) & 0xff)
+
+#define CPL_VERSION_CODE CPL_VERSION(6,1,1)
+
+typedef int cpl_error_code, cpl_errorstate, cpl_boolean, cpl_frame_group,
+ cpl_parameter_mode, cpl_parameter_class, cpl_type, cpl_msg_severity;
+typedef size_t cpl_size;
+typedef void cpl_pluginlist, cpl_frameset, cpl_frame,
+ cpl_parameter, cpl_parameterlist, cpl_recipeconfig;
+
+typedef struct _cpl_plugin_ cpl_plugin;
+typedef int (*cpl_plugin_func)(cpl_plugin *);
+struct _cpl_plugin_ {
+ unsigned int api;
+ unsigned long version;
+ unsigned long type;
+ const char *name;
+ const char *synopsis;
+ const char *description;
+ const char *author;
+ const char *email;
+ const char *copyright;
+ cpl_plugin_func initialize;
+ cpl_plugin_func execute;
+ cpl_plugin_func deinitialize;
+};
+
+struct _cpl_recipe_ {
+ cpl_plugin interface;
+ cpl_parameterlist *parameters;
+ cpl_frameset *frames;
+};
+typedef struct _cpl_recipe_ cpl_recipe;
+
+unsigned int cpl_version_get_major(void);
+unsigned int cpl_version_get_minor(void);
+unsigned int cpl_version_get_micro(void);
+
+void cpl_init(unsigned);
+const char * cpl_get_description(unsigned);
+int cpl_memory_is_empty(void);
+void cpl_memory_dump(void);
+void cpl_free(void *);
+const char *cpl_plugin_get_author(const cpl_plugin *self);
+const char *cpl_plugin_get_copyright(const cpl_plugin *self);
+cpl_plugin_func cpl_plugin_get_deinit(const cpl_plugin *self);
+const char *cpl_plugin_get_description(const cpl_plugin *self);
+const char *cpl_plugin_get_email(const cpl_plugin *self);
+cpl_plugin_func cpl_plugin_get_exec(const cpl_plugin *self);
+cpl_plugin_func cpl_plugin_get_init(const cpl_plugin *self);
+const char *cpl_plugin_get_name(const cpl_plugin *self);
+const char *cpl_plugin_get_synopsis(const cpl_plugin *self);
+unsigned long cpl_plugin_get_version(const cpl_plugin *self);
+char *cpl_plugin_get_version_string(const cpl_plugin *self);
+void cpl_pluginlist_delete(cpl_pluginlist *);
+cpl_plugin *cpl_pluginlist_find(cpl_pluginlist *, const char *);
+cpl_plugin *cpl_pluginlist_get_first(cpl_pluginlist *);
+cpl_plugin *cpl_pluginlist_get_next(cpl_pluginlist *);
+cpl_pluginlist *cpl_pluginlist_new(void);
+cpl_error_code cpl_dfs_update_product_header(cpl_frameset *);
+
+void cpl_msg_error(const char *, const char *, ...);
+cpl_error_code cpl_error_get_code(void);
+const char *cpl_error_get_file(void);
+const char *cpl_error_get_function(void);
+unsigned cpl_error_get_line(void);
+const char *cpl_error_get_message(void);
+void cpl_error_reset(void);
+cpl_error_code
+cpl_error_set_message_macro(const char *, cpl_error_code,
+ const char *, unsigned,
+ const char *, ...);
+void cpl_errorstate_dump(cpl_errorstate,
+ cpl_boolean,
+ void (*)(unsigned, unsigned, unsigned));
+cpl_errorstate cpl_errorstate_get(void);
+
+const char *cpl_frame_get_filename(const cpl_frame *self);
+cpl_frame_group cpl_frame_get_group(const cpl_frame *self);
+const char *cpl_frame_get_tag(const cpl_frame *self);
+cpl_frame *cpl_frame_new(void);
+cpl_error_code cpl_frame_set_filename(cpl_frame *self, const char *filename);
+cpl_error_code cpl_frame_set_tag(cpl_frame *self, const char *tag);
+
+void cpl_frameset_delete(cpl_frameset *self);
+cpl_frame *cpl_frameset_get_frame(cpl_frameset *self, cpl_size position);
+cpl_size cpl_frameset_get_size(const cpl_frameset *self);
+cpl_error_code cpl_frameset_insert(cpl_frameset *self, cpl_frame *frame);
+cpl_frameset *cpl_frameset_new(void);
+void cpl_msg_set_level(cpl_msg_severity);
+cpl_error_code cpl_msg_set_log_level(cpl_msg_severity);
+cpl_error_code cpl_msg_set_log_name(const char *);
+cpl_error_code cpl_msg_stop_log(void);
+
+const char *cpl_parameter_get_alias(const cpl_parameter *self,
+ cpl_parameter_mode mode);
+cpl_parameter_class cpl_parameter_get_class(const cpl_parameter *self);
+const char *cpl_parameter_get_context(const cpl_parameter *self);
+int cpl_parameter_get_default_bool(const cpl_parameter *self);
+int cpl_parameter_get_default_int(const cpl_parameter *self);
+double cpl_parameter_get_default_double(const cpl_parameter *self);
+const char *cpl_parameter_get_default_string(const cpl_parameter *self);
+int cpl_parameter_get_enum_size(const cpl_parameter *self);
+int cpl_parameter_get_enum_int(const cpl_parameter *self, int position);
+double cpl_parameter_get_enum_double(const cpl_parameter *self, int position);
+const char *cpl_parameter_get_enum_string(const cpl_parameter *self,
+ int position);
+const char *cpl_parameter_get_help(const cpl_parameter *self);
+const char *cpl_parameter_get_name(const cpl_parameter *self);
+int cpl_parameter_get_range_min_int(const cpl_parameter *self);
+double cpl_parameter_get_range_min_double(const cpl_parameter *self);
+int cpl_parameter_get_range_max_int(const cpl_parameter *self);
+double cpl_parameter_get_range_max_double(const cpl_parameter *self);
+cpl_type cpl_parameter_get_type(const cpl_parameter *self);
+cpl_error_code cpl_parameter_set_bool(cpl_parameter *self, int value);
+cpl_error_code cpl_parameter_set_int(cpl_parameter *self, int value);
+cpl_error_code cpl_parameter_set_double(cpl_parameter *self, double value);
+cpl_error_code cpl_parameter_set_string(cpl_parameter *self,
+ const char *value);
+cpl_parameter *cpl_parameterlist_find(cpl_parameterlist *self,
+ const char *name);
+cpl_parameter *cpl_parameterlist_get_first(cpl_parameterlist *self);
+cpl_parameter *cpl_parameterlist_get_next(cpl_parameterlist *self);
+cpl_size cpl_parameterlist_get_size(const cpl_parameterlist *self);
+
+char** cpl_recipeconfig_get_inputs(const cpl_recipeconfig* self,
+ const char* tag);
+cpl_size cpl_recipeconfig_get_min_count(const cpl_recipeconfig* self,
+ const char* tag, const char* input);
+cpl_size cpl_recipeconfig_get_max_count(const cpl_recipeconfig* self,
+ const char* tag, const char* input);
+char** cpl_recipeconfig_get_outputs(const cpl_recipeconfig* self,
+ const char* tag);
+char** cpl_recipeconfig_get_tags(const cpl_recipeconfig* self);
+const char *cpl_version_get_version(void);
+
+
+#define CPL_INIT_DEFAULT 0
+#define CPL_DESCRIPTION_DEFAULT 0
+#define CPL_MSG_OFF 4
+#define CPL_FALSE 0
+#define CPL_ERROR_NONE 0
+#define CPL_ERROR_FILE_NOT_CREATED 8
+#define CPL_FRAME_GROUP_PRODUCT 3
+#define CPL_PARAMETER_CLASS_ENUM (1 << 3)
+#define CPL_PARAMETER_CLASS_RANGE (1 << 2)
+#define CPL_PARAMETER_MODE_CLI (1 << 0)
+#define CPL_TYPE_BOOL (1 << 7)
+#define CPL_TYPE_DOUBLE (1 << 17)
+#define CPL_TYPE_INT (1 << 10)
+#define CPL_TYPE_STRING ((1 << 5)|(1 << 0))
+
+#endif /* CPL_API_H */
diff --git a/cpl/dfs.py b/cpl/dfs.py
index c3fba86..7b8b10c 100644
--- a/cpl/dfs.py
+++ b/cpl/dfs.py
@@ -34,29 +34,33 @@ class ProcessingInfo(object):
.. attribute:: calib
Calibration frames from a FITS file processed with CPL.
- The result of this function may directly set as :attr:`Recipe.calib`
+ The result of this function may directly set as :attr:`cpl.Recipe.calib`
attribute::
import cpl
myrecipe = cpl.Recipe('muse_bias')
myrecipe.calib = cpl.dfs.ProcessingInfo('MASTER_BIAS_0.fits').calib
- .. note:: This will not work properly for files that had
- :attr:`pyfits.HDUlist` inputs since they have assigned a temporary
+ .. note::
+
+ This will not work properly for files that had
+ :class:`pyfits.HDUList` inputs since they have assigned a temporary
file name only.
.. attribute:: raw
Raw (input) frames
- .. note:: This will not work properly for files that had
- :attr:`pyfits.HDUlist` inputs since they have assigned a temporary
+ .. note::
+
+ This will not work properly for files that had
+ :class:`pyfits.HDUList` inputs since they have assigned a temporary
file name only.
.. attribute:: param
Processing parameters.
- The result of this function may directly set as :attr:`Recipe.param`
+ The result of this function may directly set as :attr:`cpl.Recipe.param`
attribute::
import cpl
@@ -73,17 +77,19 @@ class ProcessingInfo(object):
MD5 sums of the input and calibration files. :class:`dict` with the
file name as key and the corresponding MD5 sum as value.
- .. note:: Due to a design decision in CPL, the raw input files are not
+ .. note::
+
+ Due to a design decision in CPL, the raw input files are not
accompanied with the MD5 sum.
'''
def __init__(self, source, datapaths = None):
'''
:param source: Object pointing to the result file header
- :type source: :class:`str` or :class:`PyFits.HDUList`
- or :class:`PyFits.PrimaryHDU` or :class:`PyFits.Header`
+ :type source: :class:`str` or :class:`pyfits.HDUList`
+ or :class:`pyfits.PrimaryHDU` or :class:`pyfits.Header`
:param datapaths: Dictionary with frame tags as keys and directory paths
- as values to provide a full path for the raw and
+ as values to provide a full path for the raw and
calibration frames. Optional.
:type datapaths: :class:`dict`
'''
diff --git a/cpl/esorex.py b/cpl/esorex.py
index 924f460..3201c26 100644
--- a/cpl/esorex.py
+++ b/cpl/esorex.py
@@ -1,36 +1,36 @@
-'''This module contains some limited support for reading esorex SOF and
-configuration files.
-
-Esorex is a standard execution environment for CPL recipes provided by
-ESO. See http://www.eso.org/sci/software/cpl/esorex.html for
-details.
+'''`EsoRex <http://www.eso.org/sci/software/cpl/esorex.html>`_ is a standard
+execution environment for CPL recipes provided by `ESO <http://www.eso.org>`_.
'''
import os
import cpl
+import logging
def load_sof(source):
- '''Read an esorex sof file.
+ '''Read an :program:`EsoRex` SOF file.
- :param source: SOF file object or string with sof file content.
+ :param source: SOF ("Set Of Files") file object or string with SOF
+ file content.
:type source: :class:`str` or :class:`file`
These files contain the raw and calibration files for a recipe. The
content of the file is returned as a map with the tag as key and the list
of file names as value.
- The result of this function may directly set as :attr:`Recipe.calib`
+ The result of this function may directly set as :attr:`cpl.Recipe.calib`
attribute::
import cpl
myrecipe = cpl.Recipe('muse_bias')
myrecipe.calib = cpl.esorex.read_sof(file('muse_bias.sof'))
+
+ .. note::
- .. note:: The raw data frame is silently ignored wenn setting
- :attr:`Recipe.calib` for MUSE recipes. Other recipes ignore ths raw data
- frame only if it was set manually as :attr:`Recipe.tag` or in
- :attr:`Recipe.tags` since there is no way to automatically distinguish
- between them.
+ The raw data frame is silently ignored wenn setting
+ :attr:`cpl.Recipe.calib` for MUSE recipes. Other recipes ignore the raw
+ data frame only if it was set manually as :attr:`cpl.Recipe.tag` or in
+ :attr:`cpl.Recipe.tags` since there is no way to automatically
+ distinguish between them.
'''
if isinstance(source, str):
@@ -55,27 +55,24 @@ def load_sof(source):
source.__class__.__name__)
def load_rc(source = None):
- '''Read an esorex configuration file.
+ '''Read an :program:`EsoRex` configuration file.
:param source: Configuration file object, or string with file content.
- If not set, the esorex config file
+ If not set, the :program:`EsoRex` config file
:file:`~/.esorex/esorex.rc` is used.
:type source: :class:`str` or :class:`file`
- These files contain configuration parameters for esorex or recipes. The
- content of the file is returned as a map with the (full) parameter name as
- key and its setting as string value.
+ These files contain configuration parameters for :program:`EsoRex` or
+ recipes. The content of the file is returned as a map with the (full)
+ parameter name as key and its setting as string value.
- The result of this function may directly set as :attr:`Recipe.param`
+ The result of this function may directly set as :attr:`cpl.Recipe.param`
attribute::
import cpl
myrecipe = cpl.Recipe('muse_bias')
myrecipe.param = cpl.esorex.load_rc('muse_bias.rc')
- .. note:: Unknown parameters are silently ignored wenn setting
- :attr:`Recipe.param`.
-
'''
if source is None:
source = file(os.path.expanduser('~/.esorex/esorex.rc'))
@@ -96,7 +93,7 @@ def load_rc(source = None):
source.__class__.__name__)
def init(source = None):
- '''Set the message verbosity and recipe search path from the
+ '''Set up the logging and the recipe search path from the
:file:`esorex.rc` file.
:param source: Configuration file object, or string with file content.
@@ -108,5 +105,176 @@ def init(source = None):
if rc.has_key('esorex.caller.recipe-dir'):
cpl.Recipe.path = rc['esorex.caller.recipe-dir'].split(':')
if rc.has_key('esorex.caller.msg-level'):
- cpl.msg.level = cpl.log.level[rc['esorex.caller.msg-level'].upper()]
+ msg.level = rc['esorex.caller.msg-level']
+ if rc.has_key('esorex.caller.log-level'):
+ log.level = rc['esorex.caller.log-level']
+ if rc.has_key('esorex.caller.log-dir'):
+ log.dir = rc['esorex.caller.log-dir']
+ if rc.has_key('esorex.caller.log-file'):
+ log.filename = rc['esorex.caller.log-file']
+
+class CplLogger(object):
+ DEBUG = logging.DEBUG
+ INFO = logging.INFO
+ WARN = logging.WARN
+ ERROR = logging.ERROR
+ OFF = logging.CRITICAL + 1
+
+ def __init__(self, msg = True):
+ self.handler = None
+ self._component = False
+ self._time = False
+ self._threadid = False
+ self.format = None
+ self._filename = None
+ self.dir = None
+ self._msg = msg
+ self._level = CplLogger.OFF
+
+ def _init_handler(self):
+ if not self.handler:
+ if self._msg:
+ self.handler = logging.StreamHandler()
+ elif self._filename:
+ if self.dir:
+ fname = os.path.join(self.dir, self._filename)
+ self.handler = logging.FileHandler(fname)
+ else:
+ self.handler = logging.FileHandler(self._filename)
+ else:
+ self.handler = None
+ if self.handler:
+ logging.getLogger().addHandler(self.handler)
+ self.handler.setFormatter(logging.Formatter(self.format,
+ '%H:%M:%S'))
+
+ def _shutdown_handler(self):
+ if self.handler:
+ logging.getLogger().removeHandler(self.handler)
+ self.handler = None
+
+ @property
+ def level(self):
+ '''Log level for output to the terminal. Any of
+ [ DEBUG, INFO, WARN, ERROR, OFF ].
+ '''
+ return self._level
+
+ @level.setter
+ def level(self, level):
+ if isinstance(level, (str, unicode)):
+ level = cpl.logger.level[level.upper()]
+ if level == CplLogger.OFF:
+ self._shutdown_handler()
+ else:
+ self._init_handler()
+ logging.getLogger().setLevel(logging.DEBUG)
+ if self.handler:
+ self.handler.setLevel(level)
+ self._level = level
+
+ @property
+ def format(self):
+ '''Output format.
+
+ .. seealso :: `logging.LogRecord attributes <http://docs.python.org/library/logging.html#logrecord-attributes>`_
+
+ Key mappings in the logging output.'''
+ return self._format
+
+ @format.setter
+ def format(self, fmt):
+ if fmt == None:
+ fmt = '%(asctime)s ' if self._time else ''
+ fmt += '[%(levelname)7s]'
+ fmt += '[%(threadName)s] ' if self._threadid else ' '
+ fmt += '%(name)s: ' if self._component else ''
+ fmt += '%(message)s'
+ if self.handler:
+ self.handler.setFormatter(logging.Formatter(fmt, '%H:%M:%S'))
+ self._format = fmt
+
+ @property
+ def component(self):
+ '''If :obj:`True`, attach the component name to output messages.
+ '''
+ return self._component
+ @component.setter
+ def component(self, enable):
+ self._component = enable
+ self.format = None
+
+ @property
+ def time(self):
+ '''If :obj:`True`, attach a time tag to output messages.
+ '''
+ return self._time
+
+ @time.setter
+ def time(self, enable):
+ self._time = enable
+ self.format = None
+
+ @property
+ def threadid(self):
+ '''If :obj:`True`, attach a thread tag to output messages.
+ '''
+ return self._threadid
+
+ @threadid.setter
+ def threadid(self, enable):
+ self._threadid = enable
+ self.format = None
+
+ @property
+ def filename(self):
+ '''Log file name.
+ '''
+ return self._filename
+
+ @filename.setter
+ def filename(self, name):
+ if self._msg:
+ raise AttributeError('Cannot set file name of message output')
+ if self._filename != name:
+ self._shutdown_handler()
+ self._filename = name
+ self._init_handler()
+
+ def __repr__(self):
+ return 'cpl.esorex.CplLogger(msg=%s)' % `self._msg`
+
+msg = CplLogger(msg = True)
+'''This variable is a :class:`CplLogger` instance that provides a convienience
+stream handler similar to the terminal logging functionality of the CPL. It
+basically does the same as::
+
+ import logging
+
+ log = logging.getLogger()
+ log.setLevel(logging.INFO)
+ ch = logging.StreamHandler()
+ ch.setLevel(logging.INFO)
+ ch.setFormatter(logging.Formatter('[%(levelname)7s] %(message)s'))
+ log.addHandler(ch)
+'''
+
+log = CplLogger(msg = False)
+'''This variable is a :class:`CplLogger` instance that provides a convienience
+file handler similar to the file logging functionality of the CPL. It
+basically does the same as::
+
+ import logging
+
+ log = logging.getLogger()
+ log.setLevel(logging.INFO)
+ ch = logging.FileHandler(filename)
+ ch.setLevel(logging.INFO)
+ ch.setFormatter(logging.Formatter('%(asctime)s [%(levelname)7s] %(funcName)s: %(message)s'))
+ log.addHandler(ch)
+'''
+log.threadid = True
+log.component = True
+log.time = True
+log.level = log.INFO
diff --git a/cpl/frames.py b/cpl/frames.py
index 2ab4240..ad4b8be 100644
--- a/cpl/frames.py
+++ b/cpl/frames.py
@@ -25,16 +25,16 @@ class FrameConfig(object):
.. attribute:: min
- Minimal number of frames, or :attr:`None` if not specified. A frame is
+ Minimal number of frames, or :obj:`None` if not specified. A frame is
required if the :attr:`min` is set to a value greater than 0.
.. attribute:: max
- Maximal number of frames, or :attr:`None` if not specified
+ Maximal number of frames, or :obj:`None` if not specified
.. attribute:: frames
- List of frames (file names or pyfits.HDUList objects) that are
+ List of frames (file names or :class:`pyfits.HDUList` objects) that are
assigned to this frame type.
'''
def __init__(self, tag, min_frames = 0, max_frames = 0, frames = None):
@@ -86,7 +86,7 @@ class FrameList(object):
self._recipe = recipe
self._values = dict()
if isinstance(other, self.__class__):
- self._set_items((o.name, o.value) for o in other)
+ self._set_items((o.tag, o.frames) for o in other)
elif isinstance(other, dict):
self._set_items(other.iteritems())
elif other:
@@ -94,11 +94,7 @@ class FrameList(object):
def _set_items(self, l):
for o in l:
- if o[1] is not None:
- try:
- self[o[0]] = o[1]
- except:
- pass
+ self[o[0]] = o[1]
@property
def _cpl_dict(self):
@@ -174,21 +170,11 @@ class FrameList(object):
r += '%s: %s\n' % (self._key(s), s.__doc__)
return r
- def _aslist(self, **ndata):
- frames = dict()
- for f in self:
- frames[f.tag] = f.frames
- if ndata:
- for name, tdata in ndata.items():
- if name.startswith('calib_'):
- tag = name.split('_', 1)[1]
- frames[tag] = tdata
- try:
- for name, tdata in ndata['calib'].items():
- frames[name] = tdata
- except KeyError:
- pass
- return list(frames.iteritems())
+ def _aslist(self, frames):
+ flist = FrameList(self._recipe, self)
+ if frames is not None:
+ flist._set_items(frames.items())
+ return [(f.tag, f.frames) for f in flist]
def mkabspath(frames, tmpdir):
'''Convert all filenames in the frames list into absolute paths.
diff --git a/cpl/log.py b/cpl/log.py
deleted file mode 100644
index 2a2ada4..0000000
--- a/cpl/log.py
+++ /dev/null
@@ -1,249 +0,0 @@
-import datetime
-import logging
-import os
-import sys
-import tempfile
-import threading
-
-import CPL_recipe
-
-class NullHandler(logging.Handler):
- def emit(self, record):
- pass
-
-logging.getLogger('cpl').addHandler(NullHandler())
-
-level = { "DEBUG":logging.DEBUG, "INFO":logging.INFO, "WARNING":logging.WARN,
- "ERROR":logging.ERROR }
-
-class LogServer(threading.Thread):
-
- def __init__(self, name, level):
- threading.Thread.__init__(self)
- self.name = name
- self.logger = logging.getLogger(name)
- self.level = CplLogger.verbosity.index(level)
- self.entries = LogList()
- tmphdl, self.logfile = tempfile.mkstemp(prefix = 'cpl', suffix='.log')
- os.close(tmphdl)
- os.remove(self.logfile)
- os.mkfifo(self.logfile)
- self.start()
-
- def run(self):
- try:
- logfile = open(self.logfile, buffering = 0)
- except:
- pass
- try:
- line = logfile.readline()
- os.remove(self.logfile)
- while line:
- self.log(line)
- line = logfile.readline()
- except:
- pass
-
- def log(self, s):
- try:
- creation_date = datetime.datetime.combine(
- datetime.date.today(),
- datetime.time(int(s[0:2]),int(s[3:5]),int(s[6:8])))
- lvl = level.get(s[10:17].strip(), logging.NOTSET)
- func = s[19:].split(':', 1)[0]
- msg = s[19:].split(':', 1)[1][1:-1]
- if msg.startswith('[tid='):
- threadid = int(msg[5:8])
- msg = msg[10:] if threadid > 0 else msg[12:]
- else:
- threadid = None
- log = logging.getLogger('%s.%s' % (self.logger.name, func))
- record = logging.LogRecord(log.name, lvl, None, None, msg,
- None, None, func)
- created = float(creation_date.strftime('%s'))
- if record.created < created:
- created -= 86400
- record.relativeCreated -= record.msecs
- record.relativeCreated += 1000*(created - record.created + 1)
- record.created = created
- record.msecs = 0.0
- record.threadid = threadid
- record.threadName = ('Cpl-%03i' % threadid) if threadid else 'CplThread'
- self.entries.append(record)
- if log.isEnabledFor(lvl) and log.filter(record):
- log.handle(record)
- except:
- pass
-
-class LogList(list):
- '''List of log messages.
-
- Accessing this :class:`list` directly will return the
- :class:`logging.LogRecord` instances.
-
- Example::
-
- res = muse_bias(bias_frames)
- for logrecord in res.log:
- print '%s: %s' % (entry.funcname, entry.msg)
-
- To get them formatted as string, use the :attr:`error`, :attr:`warning`,
- :attr:`info` or :attr:`debug` attributes::
-
- res = muse_bias(bias_frames)
- for line in res.log.info:
- print line
-
- '''
- def filter(self, level):
- return [ '%s: %s' % (entry.funcName, entry.msg) for entry in self
- if entry.levelno >= level ]
-
- @property
- def error(self):
- '''Error messages as list of :class:`str`
- '''
- return self.filter(logging.ERROR)
-
- @property
- def warning(self):
- '''Warnings and error messages as list of :class:`str`
- '''
- return self.filter(logging.WARN)
-
- @property
- def info(self):
- '''Info, warning and error messages as list of :class:`str`
- '''
- return self.filter(logging.INFO)
-
- @property
- def debug(self):
- '''Debug, info, warning, and error messages as list of :class:`str`
- '''
- return self.filter(logging.DEBUG)
-
-class CplLogger(object):
- DEBUG = logging.DEBUG
- INFO = logging.INFO
- WARN = logging.WARN
- ERROR = logging.ERROR
- OFF = 101
-
- verbosity = [ DEBUG, INFO, WARN, ERROR, OFF ]
-
- _time_enabled = False
-
- def __init__(self, name = 'cpl'):
- self.name = name
-
- @property
- def level(self):
- '''Log level for output to the terminal. Any of
- [ DEBUG, INFO, WARN, ERROR, OFF ]
-
- .. deprecated:: 0.3
- Use :func:`logging.Logger.setLevel`
- '''
- return CplLogger.verbosity[CPL_recipe.get_msg_level()]
-
- @level.setter
- def level(self, level):
- CPL_recipe.set_msg_level(CplLogger.verbosity.index(level))
-
- @property
- def time(self):
- '''Specify whether time tag shall be included in the terminal output
-
- .. deprecated:: 0.3
- Use :func:`logging.Handler.setFormatter`
- '''
- return CplLogger._time_enabled
-
- @time.setter
- def time(self, enable):
- CPL_recipe.set_msg_time(enable);
- CplLogger._time_enabled = not not enable
-
- @property
- def domain(self):
- '''The domain tag in the header of the log file.
-
- .. deprecated:: 0.3
- Use :func:`logging.getLogger`
- '''
- return CPL_recipe.get_log_domain()
-
- @domain.setter
- def domain(self, domain):
- CPL_recipe.set_log_domain(domain)
-
- def log(self, level, msg, caller = None):
- if caller == None:
- caller = CPL_recipe.get_log_domain()
- logging.getLogger('%s.%s' % (self.name, caller)).log(level, msg)
- CPL_recipe.log(CplLogger.verbosity.index(level), caller, msg)
-
- def debug(self, msg, caller = None):
- '''Put a 'debug' message to the log.
-
- :param msg: Message to put
- :type msg: :class:`str`
- :param caller: Name of the function generating the message.
- :type caller: :class:`str`
-
- .. deprecated:: 0.3
- Use :func:`logging.Logger.debug`
- '''
- self.log(CplLogger.DEBUG, msg, caller)
-
- def info(self, msg, caller = None):
- '''Put an 'info' message to the log.
-
- :param msg: Message to put
- :type msg: :class:`str`
- :param caller: Name of the function generating the message.
- :type caller: :class:`str`
-
- .. deprecated:: 0.3
- Use :func:`logging.Logger.info`
- '''
- self.log(CplLogger.INFO, msg, caller)
-
- def warn(self, msg, caller = None):
- '''Put a 'warn' message to the log.
-
- :param msg: Message to put
- :type msg: :class:`str`
- :param caller: Name of the function generating the message.
- :type caller: :class:`str`
-
- .. deprecated:: 0.3
- Use :func:`logging.Logger.warn`
- '''
- self.log(CplLogger.WARN, msg, caller)
-
- def error(self, msg, caller = None):
- '''Put an 'error' message to the log.
-
- :param msg: Message to put
- :type msg: :class:`str`
- :param caller: Name of the function generating the message.
- :type caller: :class:`str`
-
- .. deprecated:: 0.3
- Use :func:`logging.Logger.error`
- '''
- self.log(CplLogger.ERROR, msg, caller)
-
- def indent_more(self):
- '''Indent the output more.'''
- CPL_recipe.log_indent_more()
-
- def indent_less(self):
- '''Indent the output less.'''
- CPL_recipe.log_indent_less()
-
-msg = CplLogger()
-lib_version = CPL_recipe.version()
-lib_description = CPL_recipe.description()
diff --git a/cpl/logger.py b/cpl/logger.py
new file mode 100644
index 0000000..3a58319
--- /dev/null
+++ b/cpl/logger.py
@@ -0,0 +1,155 @@
+import datetime
+import logging
+import os
+import re
+import sys
+import tempfile
+import threading
+
+import CPL_recipe
+
+class NullHandler(logging.Handler):
+ def emit(self, record):
+ pass
+
+logging.getLogger('cpl').addHandler(NullHandler())
+
+level = { "DEBUG":logging.DEBUG, "INFO":logging.INFO, "WARNING":logging.WARN,
+ "ERROR":logging.ERROR, "OFF":(logging.CRITICAL + 1)}
+
+cpl_verbosity = [ logging.DEBUG, logging.INFO, logging.WARN,
+ logging.ERROR, logging.CRITICAL + 1 ]
+
+class LogServer(threading.Thread):
+
+ def __init__(self, name, level = None):
+ threading.Thread.__init__(self)
+ self.name = name
+ self.logger = logging.getLogger(name)
+ self.level = cpl_verbosity.index(level) if level is not None else 0
+ self.entries = LogList()
+ self.regexp = re.compile('(\\d\\d):(\\d\\d):(\\d\\d)' +
+ '\\s\\[\\s*(\\w+)\\s*\\]' +
+ '\\s(\\w+):' +
+ '(\\s\\[tid=(\\d+)\\])?' +
+ '\\s(.+)')
+ tmphdl, self.logfile = tempfile.mkstemp(prefix = 'cpl', suffix='.log')
+ os.close(tmphdl)
+ os.remove(self.logfile)
+ os.mkfifo(self.logfile)
+ self.start()
+
+ def run(self):
+ try:
+ logfile = open(self.logfile, buffering = 0)
+ except:
+ pass
+ try:
+ line = logfile.readline()
+ os.remove(self.logfile)
+ while line:
+ self.log(line)
+ line = logfile.readline()
+ except:
+ pass
+
+ def log(self, s):
+ '''Convert CPL log messages into python log records.
+
+ A typical CPL log message looks like
+
+ 10:35:25 [WARNING] rtest: [tid=000] No file tagged with FLAT
+
+ '''
+ try:
+ m = self.regexp.match(s)
+ if m is not None:
+ g = m.groups()
+ creation_date = datetime.datetime.combine(
+ datetime.date.today(),
+ datetime.time(int(g[0]),int(g[1]),int(g[2])))
+ lvl = level.get(g[3], logging.NOTSET)
+ func = g[4]
+ log = logging.getLogger('%s.%s' % (self.logger.name, func))
+ threadid = int(g[6]) if g[6] else None
+ msg = g[-1]
+ record = logging.LogRecord(log.name, lvl, None, None,
+ msg, None, None, func)
+ created = float(creation_date.strftime('%s'))
+ if record.created < created:
+ created -= 86400
+ record.relativeCreated -= record.msecs
+ record.relativeCreated += 1000*(created - record.created + 1)
+ record.created = created
+ record.msecs = 0.0
+ record.threadid = threadid
+ record.threadName = ('Cpl-%03i' % threadid) if threadid \
+ else 'CplThread'
+ elif self.entries:
+ r0 = self.entries[-1]
+ msg = s.rstrip()
+ lvl = r0.levelno
+ log = logging.getLogger(r0.name)
+ record = logging.LogRecord(r0.name, lvl, None, None,
+ msg, None, None, r0.funcName)
+ record.relativeCreated = r0.relativeCreated
+ record.created = r0.created
+ record.msecs = r0.msecs
+ record.threadid = r0.threadid
+ record.threadName = r0.threadName
+ else:
+ return
+ self.entries.append(record)
+ if log.isEnabledFor(lvl) and log.filter(record):
+ log.handle(record)
+ except:
+ pass
+
+class LogList(list):
+ '''List of log messages.
+
+ Accessing this :class:`list` directly will return the
+ :class:`logging.LogRecord` instances.
+
+ Example::
+
+ res = muse_bias(bias_frames)
+ for logrecord in res.log:
+ print '%s: %s' % (entry.funcname, entry.msg)
+
+ To get them formatted as string, use the :attr:`error`, :attr:`warning`,
+ :attr:`info` or :attr:`debug` attributes::
+
+ res = muse_bias(bias_frames)
+ for line in res.log.info:
+ print line
+
+ '''
+ def filter(self, level):
+ return [ '%s: %s' % (entry.funcName, entry.msg) for entry in self
+ if entry.levelno >= level ]
+
+ @property
+ def error(self):
+ '''Error messages as list of :class:`str`
+ '''
+ return self.filter(logging.ERROR)
+
+ @property
+ def warning(self):
+ '''Warnings and error messages as list of :class:`str`
+ '''
+ return self.filter(logging.WARN)
+
+ @property
+ def info(self):
+ '''Info, warning and error messages as list of :class:`str`
+ '''
+ return self.filter(logging.INFO)
+
+ @property
+ def debug(self):
+ '''Debug, info, warning, and error messages as list of :class:`str`
+ '''
+ return self.filter(logging.DEBUG)
+
diff --git a/cpl/parameters.py b/cpl/param.py
similarity index 64%
rename from cpl/parameters.py
rename to cpl/param.py
index 0bd4e7a..92c54ca 100644
--- a/cpl/parameters.py
+++ b/cpl/param.py
@@ -14,7 +14,7 @@ class Parameter(object):
.. attribute:: Parameter.value
- The value of the parameter, or :attr:`None` if set to default
+ The value of the parameter, or :obj:`None` if set to default
.. attribute:: Parameter.default
@@ -38,7 +38,7 @@ class Parameter(object):
.. attribute:: Parameter.range
- The numeric range of a parameter, or :attr:`None` if the parameter range
+ The numeric range of a parameter, or :obj:`None` if the parameter range
is unlimited (readonly).
.. attribute:: Parameter.sequence
@@ -115,73 +115,91 @@ class Parameter(object):
class ParameterList(object):
- def __init__(self, recipe, other = None):
+ def __init__(self, recipe, other = None, prefix = None):
self._recipe = recipe
- self._values = dict()
- if isinstance(other, self.__class__):
- self._set_items((o.name, o.value) for o in other)
- elif isinstance(other, dict):
- self._set_items(other.iteritems())
- elif other:
+ self._dict = dict()
+ self._pars = list()
+ self._prefix = prefix
+ childs = set()
+ for name, context, fullname, desc, prange, sequence, deflt, ptype \
+ in recipe._recipe.params():
+ if prefix:
+ if name.startswith(prefix + '.'):
+ aname = name[len(prefix)+1:]
+ else:
+ continue
+ else:
+ aname = name
+ if '.' in aname:
+ aname = aname.split('.', 1)[0]
+ if prefix:
+ aname = prefix + '.' + aname
+ childs.add(aname)
+ else:
+ par = Parameter(name)
+ par._set_attributes(context, fullname, deflt,
+ desc, prange, sequence, ptype)
+ self._dict[name] = par
+ self._dict[fullname] = par
+ self._dict[self._paramname(aname)] = par
+ self._pars.append(par)
+ for name in childs:
+ clist = ParameterList(recipe, prefix = name)
+ self._dict[name] = clist
+ for par in clist._pars:
+ self._dict[par.name] = par
+ self._dict[par.fullname] = par
+ self._pars.append(par)
+ aname = self._paramname(name)
+ self._dict[aname] = clist
+ if other:
self._set_items(other)
- def _set_items(self, l):
+ def _set_items(self, other):
+ if isinstance(other, self.__class__):
+ l = ((o.name, o.value) for o in other)
+ elif isinstance(other, dict):
+ l = other.iteritems()
+ else:
+ l = other
for o in l:
- if o[1] is not None:
- try:
- self[o[0]] = o[1]
- except:
- pass
+ self[o[0]] = o[1]
- @property
- def _cpl_dict(self):
- if self._recipe is None or self._recipe._recipe is None:
- return None
- cpl_params = self._recipe._recipe.params()
- if cpl_params is None:
- return None
- s = dict()
- for pd in cpl_params:
- (name, context, fullname, desc, _range, sequence, deflt, type) = pd
- pname = name.replace('.', '_')
- if pname in s:
- continue
+ def _del_items(self):
+ for p in self:
+ del p.value
+
+ @staticmethod
+ def _paramname(s):
+ for c in [ '-', ' ' ]:
+ if isinstance(c, tuple):
+ s = s.replace(c[0], c[1])
else:
- s[pname] = self._values.setdefault(name, Parameter(name))
- s[pname]._set_attributes(context, fullname, deflt,
- desc, _range, sequence, type)
+ s = s.replace(c, '_')
return s
- @property
- def _dict(self):
- return self._cpl_dict or self._values
-
- @property
- def _dict_full(self):
- d = self._dict
- return dict(d.items() +
- [ (p.fullname, p) for p in d.values() if p.fullname ] +
- [ (p.name, p) for p in d.values() if p.name not in d])
-
def __iter__(self):
- return self._dict.itervalues()
+ return self._pars.__iter__()
def __getitem__(self, key):
- return self._dict_full[key]
+ return self._dict[key]
def __setitem__(self, key, value):
- d = self._cpl_dict
- if d is not None:
- d = dict(d.items() +
- [ (p.fullname, p) for p in d.values() if p.fullname] +
- [ (p.name, p) for p in d.values() if p.name not in d])
- d[key].value = value
+ p = self[key]
+ if isinstance(p, self.__class__):
+ if value is not None:
+ p._set_items(value)
+ else:
+ p._del_items()
else:
- self._values.setdefault(key.replace('.', '_'),
- Parameter(key)).value = value
+ p.value = value
def __delitem__(self, key):
- del self._dict_full[key].value
+ p = self[key]
+ if isinstance(p, self.__class__):
+ p._del_items()
+ else:
+ del p.value
def __str__(self):
r = ''
@@ -191,10 +209,10 @@ class ParameterList(object):
return r
def __contains__(self, key):
- return key in self._dict_full
+ return key in self._dict
def __len__(self):
- return len(self._dict)
+ return len(self._pars)
def __getattr__(self, key):
return self[key]
@@ -209,7 +227,8 @@ class ParameterList(object):
del self[key]
def __dir__(self):
- return self._dict.keys()
+ return list(set(self._paramname(d)
+ for d in self._dict.keys() if '.' not in d))
def __repr__(self):
return `list(self)`
@@ -227,25 +246,14 @@ class ParameterList(object):
p.name.rjust(maxlen), p.__doc__, `p.default`)
return r
- def _aslist(self, **ndata):
- parlist = dict([ ( param.fullname, param.value )
- for param in self
- if param.value is not None
- and (ndata is None or param.name not in ndata) ])
- if ndata:
- for name, tdata in ndata.items():
- if name.startswith('param_'):
- try:
- parlist[self[name.split('_', 1)[1]].fullname] = tdata
- except KeyError:
- pass
- try:
- for pname, tdata in ndata['param'].items():
- try:
- parlist[self[pname].fullname] = tdata
- except KeyError:
- pass
- except KeyError:
- pass
- return list(parlist.iteritems())
-
+ def _aslist(self, par):
+ parlist = ParameterList(self._recipe, self)
+ if par is not None:
+ parlist._set_items(par.items())
+ l = list()
+ for param in parlist:
+ if isinstance(param, Parameter):
+ l.append((param.fullname, param.value))
+ else:
+ l += param._aslist(par)
+ return l
diff --git a/cpl/recipes.py b/cpl/recipe.py
similarity index 77%
rename from cpl/recipes.py
rename to cpl/recipe.py
index 57c5d53..a3dd8ae 100644
--- a/cpl/recipes.py
+++ b/cpl/recipe.py
@@ -9,38 +9,34 @@ import CPL_recipe
import esorex
from frames import FrameList, mkabspath, expandframelist
from result import Result, RecipeCrash
-from parameters import ParameterList
-from log import LogServer, msg
+from param import ParameterList
+from logger import LogServer
class Recipe(object):
'''Pluggable Data Reduction Module (PDRM) from a ESO pipeline.
Recipes are loaded from shared libraries that are provided with the
- pipeline library of the instrument.
+ pipeline library of the instrument. The module does not need to be
+ linked to the same library version as the one used for the compilation
+ of python-cpl. Currently, recipes compiled with CPL versions from 4.0
+ are supported. The list of supported versions is stored as
+ :attr:`cpl.cpl_versions`.
The libraries are searched in the directories specified by the class
attribute :attr:`Recipe.path` or its subdirectories. The search path is
automatically set to the esorex path when :func:`cpl.esorex.init()`
is called.
-
- Attributes:
-
- __name__: Recipe name
- __filename__: Shared library file name
- param: Parameter list
- calib: Calibration frame list
- tag: default tag
- tags: list of possible tags
- __author__: author name
- __email__: author's email address
- description: (synopsis, description) pair
- version: (versionnumber, versionstring) pair
- memory_dump: If set to 1, a memory dump is issued to stdout if the memory was not
- totally freed after the execution. If set to 2, the dump is always issued.
- Standard is 0: nothing dumped.
'''
path = [ '.' ]
+ '''Search path for the recipes. It may be set to either a string, or to a
+ list of strings. All shared libraries in the search path and their
+ subdirectories are searched for CPL recipes. On default, the path is
+ set to the current directory.
+
+ The search path is automatically set to the esorex path when
+ :func:`cpl.esorex.init()` is called.
+ '''
def __init__(self, name, filename = None, version = None, threaded = False):
'''Try to load a recipe with the specified name in the directory
@@ -66,31 +62,51 @@ class Recipe(object):
'''
self._recipe = None
self.__name__ = name
+ '''Recipe name.'''
+
if not filename:
filename = Recipe.get_recipefilename(name, version)
if not filename:
raise IOError('Recipe %s not found at path %s'
% (`name`, `Recipe.path`))
self.__file__ = filename
+ '''Shared library file name.'''
+
self._recipe = CPL_recipe.recipe(filename, name)
if version and version not in self.version:
raise IOError('wrong version %s (requested %s) for %s in %s' %
(str(self.version), str(version), name, filename))
+ if not self._recipe.cpl_is_supported():
+ warn("Unsupported CPL version %s linked to %s" %
+ self._recipe.version()[1], filename)
self._param = ParameterList(self)
self._calib = FrameList(self)
+
+ self.env = dict()
+ '''Bla'''
+
self._tags = None
+
self.tag = self.tags[0] if self.tags else None
+ '''Default tag when the recipe is called. This is set automatically
+ only if the recipe provided the information about input
+ tags. Otherwise this tag has to be set manually.
+ '''
+
self.output_dir = None
+
self.temp_dir = '.'
+ '''Base directory for temporary directories where the recipe is
+ executed. The working dir is created as a subdir with a random file
+ name. If set to :obj:`None`, the system temp dir is used. Defaults to
+ :literal:`'.'`.
+ '''
+
self.memory_dump = 0
- self.threaded = threaded
- def reload(self):
- '''Reload the recipe.
+ self.threaded = threaded
- All recipe settings remain unchanged.
- '''
- self._recipe = CPL_recipe.recipe(self.__file__, self.__name__)
+ self.__doc__ = self._doc()
@property
def __author__(self):
@@ -119,12 +135,24 @@ class Recipe(object):
@property
def __copyright__(self):
- '''Copyright string'''
+ '''Copyright string of the recipe'''
return self._recipe.copyright()
@property
+ def cpl_version(self):
+ '''Version of the CPL library that is linked to the recipe,
+ as a string'''
+ return self._recipe.cpl_version()
+
+ @property
+ def cpl_description(self):
+ '''Version numbers of CPL and its libraries that were linked to
+ the recipe, as a string.'''
+ return self._recipe.cpl_description()
+
+ @property
def tags(self):
- '''Possible tags for the raw input frames, or ':attr:`None` if this
+ '''Possible tags for the raw input frames, or ':obj:`None` if this
information is not provided by the recipe.'''
frameconfig = self._recipe.frameConfig()
return [ c[0][0] for c in frameconfig ] if frameconfig else self._tags
@@ -167,11 +195,13 @@ class Recipe(object):
BADPIX_TABLE None None ['badpix_1.fits', 'badpix_2.fits']
MASTER_FLAT None 1 None
- .. note:: Only MUSE recipes are able to provide the full list of
+ .. note::
+
+ Only MUSE recipes are able to provide the full list of
calibration frames and the minimal/maximal number of calibration
frames. For other recipes, only frames that were set by the users are
returned here. Their minimum and maximum value will be set to
- :attr:`None`.
+ :obj:`None`.
In order to assing a FITS file to a tag, the file name or the
:class:`pyfits.HDUList` is assigned to the calibration attribute:
@@ -204,6 +234,12 @@ class Recipe(object):
>>> muse_scibasic.calib = { 'MASTER_BIAS':'master_bias_0.fits',
... 'BADPIX_TABLE':[ 'badpix_1.fits', 'badpix_2.fits' ] }
+
+ In a recipe call, the calibration frame lists may be overwritten by
+ specifying them in a :class:`dict`:
+
+ >>> res = muse_scibasic( ..., calib = {'MASTER_BIAS':'master_bias_1.fits'})
+
'''
return self._calib
@@ -249,14 +285,14 @@ class Recipe(object):
>>> muse_scibasic.param.nifu = 1
The new value is checked against parameter type, and possible value
- limitations provided by the recipe. Dots in parameter names are
+ limitations provided by the recipe. Hyphens in parameter names are
converted to underscores. In a recipe call, the same parameter can be
- specified as
+ specified as :class:`dict`:
- >>> res = muse_scibasic( ..., param_nifu = 1)
+ >>> res = muse_scibasic( ..., param = {'nifu':1})
To reset a value to its default, it is either deleted, or set to
- :attr:`None`. The following two lines:
+ :obj:`None`. The following two lines:
>>> muse_scibasic.param.nifu = None
>>> del muse_scibasic.param.nifu
@@ -282,31 +318,24 @@ class Recipe(object):
def param(self):
self._param = ParameterList(self, None)
- def output(self, tag = None):
- '''Return the list of output frame tags.
+ @property
+ def output(self):
+ '''Return a dictionary of output frame tags.
- If the recipe does not provide this information, an exception is raised.
-
- :param tag: Input (raw) frame tag. Defaults to the :attr:`Recipe.tag`
- attribute if not specified.
- :type tag: :class:`str`
+ Keys are the tag names, values are the corresponding list of output
+ tags. If the recipe does not provide this information, an exception is
+ raised.
'''
- if tag is None:
- tag = self.tag
- for c in self._recipe.frameConfig():
- if tag == c[0][0]:
- return c[2]
+ return dict((c[0][0], c[2]) for c in self._recipe.frameConfig())
def __call__(self, *data, **ndata):
'''Call the recipes execution with a certain input frame.
- :param data: Data input frames, using the default tag.
- :type data: :class:`pyfits.HDUlist` or :class:`str` or a :class:`list`
- of them.
+ :param raw: Data input frames.
+ :type raw: :class:`pyfits.HDUlist` or :class:`str` or a :class:`list`
+ of them, or :class:`dict`
:param tag: Overwrite the :attr:`tag` attribute (optional).
:type tag: :class:`str`
- :param raw: Data input frames, sorted by tag
- :type raw: :class:`dict`
:param threaded: overwrite the :attr:`threaded` attribute (optional).
:type threaded: :class:`bool`
:param loglevel: set the log level for python :mod:`logging` (optional).
@@ -315,6 +344,7 @@ class Recipe(object):
:class:`logging.Logger` (optional, default is 'cpl.' + recipename).
:type logname: :class:`str`
:param output_dir: Set or overwrite the :attr:`output_dir` attribute.
+ (optional)
:type output_dir: :class:`str`
:param param: overwrite the CPL parameters of the recipe specified
as keys with their dictionary values (optional).
@@ -322,38 +352,46 @@ class Recipe(object):
:param calib: Overwrite the calibration frame lists for the tags
specified as keys with their dictionary values (optional).
:type calib: :class:`dict`
+ :param env: overwrite environment variables for the recipe call
+ (optional).
+ :type env: :class:`dict`
:return: The object with the return frames as :class:`pyfits.HDUList`
objects
:rtype: :class:`cpl.Result`
- :raise: :class:`exceptions.ValueError` If the invocation parameters
+ :raise: :exc:`exceptions.ValueError` If the invocation parameters
are incorrect.
- :raise: :class:`exceptions.IOError` If the temporary directory could
+ :raise: :exc:`exceptions.IOError` If the temporary directory could
not be built, the recipe could not start or the files could not
- be read/written. This error is also raised if the recipe crashed
- by a segementation fault or similar.
- :raise: :class:`cpl.CplError` If the recipe returns an error.
+ be read/written.
+ :raise: :exc:`cpl.CplError` If the recipe returns an error.
+ :raise: :exc:`cpl.RecipeCrash` If the CPL recipe crashes with a
+ SIGSEV or a SIGBUS
- .. note:: If the recipe is executed in the background
+ .. note::
+
+ If the recipe is executed in the background
(``threaded = True``) and an exception occurs, this exception is
raised whenever result fields are accessed.
'''
tmpfiles = []
threaded = ndata.get('threaded', self.threaded)
- loglevel = ndata.get('loglevel', msg.DEBUG)
+ loglevel = ndata.get('loglevel')
logname = ndata.get('logname', 'cpl.%s' % self.__name__)
output_dir = ndata.get('output_dir', self.output_dir)
output_format = str if output_dir else pyfits.HDUList
if output_dir is None:
output_dir = tempfile.mkdtemp(dir = self.temp_dir,
prefix = self.__name__ + "-")
- parlist = self.param._aslist(**ndata)
+ parlist = self.param._aslist(ndata.get('param'))
raw_frames = self._get_raw_frames(*data, **ndata)
if len(raw_frames) < 1:
raise ValueError('No raw frames specified.')
input_len = -1 if isinstance(raw_frames[0][1], pyfits.HDUList) else \
len(raw_frames[0][1]) if isinstance(raw_frames[0][1], list) else -1
- calib_frames = self.calib._aslist(**ndata)
+ calib_frames = self.calib._aslist(ndata.get('calib'))
framelist = expandframelist(raw_frames + calib_frames)
+ runenv = dict(self.env)
+ runenv.update(ndata.get('env', dict()))
logger = None
delete = output_format == pyfits.HDUList
try:
@@ -368,19 +406,21 @@ class Recipe(object):
pass
raise
if not threaded:
- return self._exec(output_dir, parlist, framelist, input_len,
- logger, output_format, delete)
+ return self._exec(output_dir, parlist, framelist, runenv,
+ input_len, logger, output_format, delete)
else:
return Threaded(
- self._exec, output_dir, parlist, framelist, input_len,
- logger, output_format, delete)
+ self._exec, output_dir, parlist, framelist, runenv,
+ input_len, logger, output_format, delete)
- def _exec(self, output_dir, parlist, framelist, input_len,
- logger, output_format, delete):
+ def _exec(self, output_dir, parlist, framelist, runenv,
+ input_len, logger, output_format, delete):
try:
return Result(self._recipe.frameConfig(), output_dir,
self._recipe.run(output_dir, parlist, framelist,
- logger.logfile, logger.level, self.memory_dump),
+ runenv.items(),
+ logger.logfile, logger.level,
+ self.memory_dump),
input_len, logger, output_format)
finally:
self._cleanup(output_dir, logger, delete)
@@ -391,27 +431,23 @@ class Recipe(object):
Returns a :class:`list` with (tag, the input frame(s)) pairs. Note
that more than one input tag is not allowed here.
'''
- m = ndata.get('raw', { })
+ data = list(data)
+ if 'raw' in ndata:
+ data.append(ndata['raw'])
tag = ndata.get('tag', self.tag)
- if tag is None:
- if data:
+ m = { }
+ for f in data:
+ if isinstance(f, dict):
+ m.update(f)
+ elif tag is None:
raise ValueError('No raw input tag')
- else:
- for f in data:
- if self.tag not in m:
- m[tag] = f
- elif isinstance(m[tag], list) \
- and not isinstance(m[tag], pyfits.HDUList):
- m[tag].append(f)
- else:
- m[tag] = [ m[tag], f ]
-
- if ndata is not None:
- for name, tdata in ndata.items():
- if name.startswith('raw_'):
- tag = name.split('_', 1)[1]
- m[tag] = tdata
-
+ elif tag not in m:
+ m[tag] = f
+ elif isinstance(m[tag], list) \
+ and not isinstance(m[tag], pyfits.HDUList):
+ m[tag].append(f)
+ else:
+ m[tag] = [ m[tag], f ]
return list(m.iteritems())
def _cleanup(self, output_dir, logger, delete):
@@ -428,8 +464,7 @@ class Recipe(object):
if delete:
shutil.rmtree(output_dir)
- @property
- def __doc__(self):
+ def _doc(self):
s = '%s\n\n%s\n\n' % (self.description[0], self.description[1])
r = 'Parameters:\n'
@@ -446,10 +481,10 @@ class Recipe(object):
t = 'Raw and product frames:\n'
maxlen = max(len(f) for f in self.tags)
for f in self.tags:
- t += ' %s --> %s\n' % (f.rjust(maxlen), `self.output(f)`)
+ t += ' %s --> %s\n' % (f.rjust(maxlen), `self.output[f]`)
else:
t = ''
- print s + r + c + t + '\n\n'
+ return s + r + c + t + '\n\n'
def __repr__(self):
return 'Recipe(%s, version = %s)' % (`self.__name__`, `self.version[0]`)
@@ -500,8 +535,12 @@ class Recipe(object):
def set_maxthreads(n):
'''Set the maximal number of threads to be executed in parallel.
- .. note:: This affects only threads that are started afterwards with
+ .. note::
+
+ This affects only threads that are started afterwards with
the ``threaded = True`` flag.
+
+ .. seealso:: :ref:`parallel`
'''
Threaded.set_maxthreads(n)
diff --git a/cpl/result.py b/cpl/result.py
index 60cdb41..a22f663 100644
--- a/cpl/result.py
+++ b/cpl/result.py
@@ -104,7 +104,7 @@ class CplError(StandardError):
The exception is raised on recipe invocation, or when accessing the result
frames if the recipe was started in background
- (:attr:`cpl.Recipe.threaded` set to :attr:`True`).
+ (:attr:`cpl.Recipe.threaded` set to :obj:`True`).
Attributes:
@@ -128,11 +128,11 @@ class CplError(StandardError):
Log lines of the recipe that lead to this exception.
- .. seealso:: :class:`cpl.log.LogList`
+ .. seealso:: :class:`cpl.logger.LogList`
.. attribute:: next
- Next error, or :attr:`None`.
+ Next error, or :obj:`None`.
'''
def __init__(self, retval, res, logger = None):
@@ -187,7 +187,7 @@ class RecipeCrash(StandardError):
The exception is raised on recipe invocation, or when accessing the result
frames if the recipe was started in background
- (:attr:`cpl.Recipe.threaded` set to :attr:`True`).
+ (:attr:`cpl.Recipe.threaded` set to :obj:`True`).
Attributes:
@@ -195,7 +195,7 @@ class RecipeCrash(StandardError):
List of stack elements, with the most recent element (the one that
caused the crash) at the end. Each stack element is a
- :class:`collections.namedtuple` with the following attributes:
+ :func:`collections.namedtuple` with the following attributes:
.. attribute:: filename
diff --git a/cpl/version.py b/cpl/version.py
index 26bae34..60b30c3 100644
--- a/cpl/version.py
+++ b/cpl/version.py
@@ -1,5 +1,5 @@
-version = '0.3.8'
+version = '0.4'
author = 'Ole Streicher'
email = 'python-cpl at liska.ath.cx'
license_ = 'GPL'
-doc = 'Python interface for the Common Pipeline Library.\n\nNon-official library to access CPL modules via Python. \nIt is not meant as part of the MUSE pipeline software, but \nmay be useful for testing.'
+doc = 'Python interface for the Common Pipeline Library.\nThis module can list, configure and execute CPL-based recipes from Python.\nThe input, calibration and output data can be specified as FITS files\nor as pyfits objects in memory.\n\nThe Common Pipeline Library (CPL) comprises a set of ISO-C libraries that\nprovide a comprehensive, efficient and robust software toolkit. It forms a\nbasis for the creation of automated astronomical data-reduction tasks. One of\nthe features provided by the CPL is the ability to create data-reduction\nalgorithms that run as plugins (dynamic libraries). These are called "recipes"\nand are one of the main aspects of the CPL data-reduction development\nenvironment. More information about the CPL can be found here:\n\n http://www.eso.org/sci/software/cpl/\n\nThe interface may be used to run ESO pipeline recipes linked to CPL \nversions 4.0 to 6.2.\n\n'
diff --git a/setup.py b/setup.py
index 3a2cfba..25f332f 100644
--- a/setup.py
+++ b/setup.py
@@ -4,15 +4,28 @@ from distutils.core import setup, Extension
author = 'Ole Streicher'
email = 'python-cpl at liska.ath.cx'
license_ = 'GPL'
-cpl_version = '0.3.8'
-doc = '''Python interface for the Common Pipeline Library.
+cpl_version = '0.4'
+with open('README') as readme:
+ description = readme.read().splitlines()
+ long_description = "\n".join(description[2:])
+ description = description[0]
+
+doc = '%s\n%s' % (description,
+ long_description[:long_description.find('Build instructions')])
+pkgname = 'python-cpl'
+baseurl = 'http://www.aip.de/~oles/%s' % pkgname
+classifiers = '''Development Status :: 4 - Beta
+Intended Audience :: Science/Research
+License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
+Operating System :: MacOS :: MacOS X
+Operating System :: POSIX
+Operating System :: Unix
+Programming Language :: C
+Programming Language :: Python
+Programming Language :: Python :: 2
+Topic :: Scientific/Engineering :: Astronomy
+'''.splitlines()
-Non-official library to access CPL modules via Python.
-It is not meant as part of the MUSE pipeline software, but
-may be useful for testing.'''
-description = doc.splitlines()
-long_description = "\n".join(description[2:])
-description = description[0]
def create_version_file(cpl_version = cpl_version):
vfile = open(os.path.join('cpl', 'version.py'), 'w')
@@ -22,20 +35,25 @@ def create_version_file(cpl_version = cpl_version):
vfile.write("license_ = %s\n" % repr(license_))
vfile.write("doc = %s\n" % repr(doc))
vfile.close()
-include_dirs = os.environ.get('INCLUDE_PATH', '.').split(':')
-library_dirs = os.environ.get('LIBRARY_PATH', '.').split(':')
-module1 = Extension('cpl.CPL_recipe',
- include_dirs = include_dirs,
- library_dirs = library_dirs,
- libraries = [ 'cplcore', 'cpldfs', 'cplui', 'cpldrs',
- 'gomp', 'mcheck' ],
- sources = ['cpl/CPL_recipe.c'])
create_version_file()
-setup (name = 'python-cpl',
- version = cpl_version, author = author, author_email = email,
- description = description, long_description = long_description,
- license = license_, url = 'http://www.aip.de/~oles/python-cpl/',
- packages = ['cpl'],
- ext_modules = [module1])
+module1 = Extension('cpl.CPL_recipe',
+ sources = ['cpl/CPL_recipe.c', 'cpl/CPL_library.c'])
+
+setup(
+ name = pkgname,
+ version = cpl_version,
+ author = author,
+ author_email = email,
+ description = description,
+ long_description = long_description,
+ license = license_,
+ url = baseurl,
+ download_url = '%s/%s-%s.tar.gz' % (baseurl, pkgname, cpl_version),
+ classifiers = classifiers,
+ requires = ['pyfits'],
+ provides = ['cpl'],
+ packages = ['cpl'],
+ ext_modules = [module1]
+ )
--
Control pipeline recipes from the European Southern Observatory
More information about the debian-science-commits
mailing list