diff --git a/pyext/GApplicationPars.i b/pyext/GApplicationPars.i index abf7792..eed4773 100644 --- a/pyext/GApplicationPars.i +++ b/pyext/GApplicationPars.i @@ -1,7 +1,7 @@ /*************************************************************************** * GApplicationPars.i - Application parameter container * * ----------------------------------------------------------------------- * - * copyright (C) 2010-2016 by Juergen Knoedlseder * + * copyright (C) 2010-2017 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * @@ -36,7 +36,7 @@ * * @brief Application parameter container class ***************************************************************************/ -class GApplicationPars : public GBase { +class GApplicationPars : public GContainer { public: // Constructors and destructors @@ -76,9 +76,14 @@ public: ***************************************************************************/ %extend GApplicationPars { GApplicationPar& __getitem__(const int& index) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { return (*self)[index]; } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + return (*self)[self->size()+index]; + } else { throw GException::out_of_range("__getitem__(int)", index, self->size()); } @@ -86,11 +91,45 @@ public: GApplicationPar& __getitem__(const std::string& name) { return (*self)[name]; } + GApplicationPars* __getitem__(PyObject *param) { + if (PySlice_Check(param)) { + Py_ssize_t start = 0; + Py_ssize_t stop = 0; + Py_ssize_t step = 0; + Py_ssize_t len = self->size(); + if (PySlice_GetIndices((PySliceObject*)param, len, &start, &stop, &step) == 0) { + GApplicationPars* pars = new GApplicationPars; + if (step > 0) { + for (int i = (int)start; i < (int)stop; i += (int)step) { + pars->append((*self)[i]); + } + } + else { + for (int i = (int)start; i > (int)stop; i += (int)step) { + pars->append((*self)[i]); + } + } + return pars; + } + else { + throw GException::invalid_argument("__getitem__(PyObject)", + "Invalid slice indices"); + } + } + else { + throw GException::invalid_argument("__getitem__(PyObject)",""); + } + } void __setitem__(const int& index, const GApplicationPar& par) { - if (index>=0 && index < self->size()) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { (*self)[index] = par; return; } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + (*self)[self->size()+index] = par; + } else { throw GException::out_of_range("__setitem__(int)", index, self->size()); } diff --git a/pyext/GModels.i b/pyext/GModels.i index 75f7733..8bae192 100644 --- a/pyext/GModels.i +++ b/pyext/GModels.i @@ -125,9 +125,13 @@ public: } } void __setitem__(const int& index, const GModel& val) { + // Counting from start, e.g. [2] if (index >= 0 && index < self->size()) { self->set(index, val); - return; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + self->set(self->size()+index, val); } else { throw GException::out_of_range("__setitem__(int)", "Model index", diff --git a/pyext/GObservations.i b/pyext/GObservations.i index 6d602a8..c25f423 100644 --- a/pyext/GObservations.i +++ b/pyext/GObservations.i @@ -151,9 +151,13 @@ typedef GObservations::likelihood likelihood; } } void __setitem__(const int& index, const GObservation& val) { - if (index>=0 && index < self->size()) { + // Counting from start, e.g. [2] + if (index >= 0 && index < self->size()) { self->set(index, val); - return; + } + // Counting from end, e.g. [-1] + else if (index < 0 && self->size()+index >= 0) { + self->set(self->size()+index, val); } else { throw GException::out_of_range("__setitem__(int)", index, self->size()); diff --git a/test/Makefile.am b/test/Makefile.am index c6f8d8d..f72ca28 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -120,7 +120,8 @@ EXTRA_DIST = data reports testinst \ test_GXml.py \ test_GXspec.py \ test_examples.py \ - test_python.py + test_python.py \ + test_support.py # Standard test sources and links test_GSupport_SOURCES = test_GSupport.cpp test_GSupport.hpp diff --git a/test/test_GApplication.py b/test/test_GApplication.py index 955cd43..b6ffc01 100755 --- a/test/test_GApplication.py +++ b/test/test_GApplication.py @@ -1,7 +1,7 @@ # ========================================================================== # This module performs unit tests for the GammaLib application module # -# Copyright (C) 2012-2016 Juergen Knoedlseder +# Copyright (C) 2012-2017 Juergen Knoedlseder # # 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 @@ -19,6 +19,7 @@ # ========================================================================== import os import gammalib +import test_support # ========================================== # @@ -42,8 +43,7 @@ class Test(gammalib.GPythonTestSuite): # Return return - - # Private methods + # Check log file versus a reference def _check_log_file(self, ref, calls): """ Check log file versus a reference @@ -74,24 +74,28 @@ class Test(gammalib.GPythonTestSuite): # Return return - - # Public methods - def set(self): - """ - Set all test functions + # Setup GApplicationPars container + def _setup_pars(self): """ - # Set test name - self.name('app') + Setup GApplicationPars container - # Append tests - self.append(self.test_log, 'Test GLog') - self.append(self.test_app, 'Test GApplication') - self.append(self.test_pars, 'Test GApplicationPars') + Returns + ------- + pars : `~gammalib.GApplicationPars` + Parameter container + """ + # Setup application parameter container + pars = gammalib.GApplicationPars() + for i in range(10): + name = '%s' % i + par = gammalib.GApplicationPar(name,'r','a','1.0','0.0','2.0','Dummy') + pars.append(par) - # Return - return + # Return application parameter container + return pars - def test_log(self): + # Test GLog class + def _test_log(self): """ Test GLog class """ @@ -192,7 +196,8 @@ class Test(gammalib.GPythonTestSuite): # Return return - def test_app(self): + # Test GApplication class + def _test_app(self): """ Test GApplication class """ @@ -224,7 +229,8 @@ class Test(gammalib.GPythonTestSuite): # Return return - def test_pars(self): + # Test GApplicationPars class + def _test_pars(self): """ Test GApplicationPars class """ @@ -240,3 +246,59 @@ class Test(gammalib.GPythonTestSuite): # Return return + + # Test GApplicationPars class access operators + def _test_pars_access(self): + """ + Test GApplicationPars class model access + """ + # Setup application parameter container + pars = self._setup_pars() + + # Perform application parameter access tests + test_support._container_access_index(self, pars) + + # Check application parameter setting by index from start + par = gammalib.GApplicationPar('98','r','a','1.0','0.0','2.0','Dummy') + pars[3] = par + self.test_value(pars[3].name(), '98') + + # Check application parameter setting by index from end + par = gammalib.GApplicationPar('99','r','a','1.0','0.0','2.0','Dummy') + pars[-2] = par + self.test_value(pars[-2].name(), '99') + + # Return + return + + # Test GApplicationPars class slicing + def _test_pars_slicing(self): + """ + Test GApplicationPars class slicing + """ + # Setup application parameter container + pars = self._setup_pars() + + # Perform slicing tests + test_support._container_slicing(self, pars) + + # Return + return + + # Set test functions + def set(self): + """ + Set all test functions + """ + # Set test name + self.name('app') + + # Append tests + self.append(self._test_log, 'Test GLog') + self.append(self._test_app, 'Test GApplication') + self.append(self._test_pars, 'Test GApplicationPars') + self.append(self._test_pars_access, 'Test GApplicationPars class parameter access') + self.append(self._test_pars_access, 'Test GApplicationPars class slicing') + + # Return + return diff --git a/test/test_GModel.py b/test/test_GModel.py index 9c396f1..e2415f4 100755 --- a/test/test_GModel.py +++ b/test/test_GModel.py @@ -17,8 +17,8 @@ # along with this program. If not, see . # # ========================================================================== -import os import gammalib +import test_support # ==================================== # @@ -36,134 +36,87 @@ class Test(gammalib.GPythonTestSuite): # Call base class constructor gammalib.GPythonTestSuite.__init__(self) - # Set test data directory - self._datadir = os.environ['TEST_DATA'] - # Return return - # Set test functions - def set(self): + # Setup GModels container + def _setup_models(self): """ - Set all test functions - """ - # Set test name - self.name('model') - - # Append tests - self.append(self.test_models_access, 'Test GModels class model access') - self.append(self.test_models_slicing, 'Test GModels class slicing') - - # Return - return + Setup GModels container - # Test function - def test_models_access(self): - """ - Test GModels class model access + Returns + ------- + models : `~gammalib.GModels` + Models container """ - # Set model filename - filename = self._datadir + '/model_point_plaw.xml' - - # Read model container and create a copy of its first model (the - # copy is needed since the model container will go out of scope - # later) - models = gammalib.GModels(filename) - model = models[0].copy() - name = model.name() - - # Create an empty model container + # Setup model container models = gammalib.GModels() - - # Append 10 identical models to model container + model = gammalib.GModelSky() for i in range(10): - model.name(name+'_'+str(i)) + model.name('%s' % i) models.append(model) - - # Loop over all models using the container iterator and count the - # number of iterations - nmodels = 0 - for m in models: - self.test_value(m.name(), name+'_'+str(nmodels)) - nmodels += 1 - # Check that looping was successful - self.test_value(models.size(), 10, 'Check model container size') - self.test_value(nmodels, 10, 'Check model iterator') + # Return model container + return models - # Check model access from end - self.test_value(models[-1].name(), name+'_9') + # Test GModels class access operators + def _test_models_access(self): + """ + Test GModels class model access + """ + # Setup model container and sky model + models = self._setup_models() + model = gammalib.GModelSky() - # Check model access by name - self.test_value(models[name+'_7'].name(), name+'_7') + # Perform model access tests + test_support._container_access_index(self, models) - # Check model setting by index - model.name('Test index') - models[0] = model - self.test_value(models[0].name(), 'Test index') + # Check model getting by name + self.test_value(models['7'].name(), '7') # Check model setting by name model.name('Test name') - models[name+'_3'] = model + models['3'] = model self.test_value(models['Test name'].name(), 'Test name') + # Check model setting by index from start + model.name('Test index from start') + models[1] = model + self.test_value(models[1].name(), 'Test index from start') + + # Check model setting by index from end + model.name('Test index from end') + models[-2] = model + self.test_value(models[-2].name(), 'Test index from end') + # Return return - # Test GModels class slicing - def test_models_slicing(self): + def _test_models_slicing(self): """ Test GModels class slicing """ - # Setup model container - models = gammalib.GModels() - model = gammalib.GModelSky() - for i in range(10): - model.name('%s' % i) - models.append(model) + # Setup models container + models = self._setup_models() - # Test models[start:end] - self.test_value(len(models[3:5]), 2) - self.test_value(models[3:5][0].name(), '3') - self.test_value(models[3:5][1].name(), '4') + # Perform slicing tests + test_support._container_slicing(self, models) - # Test models[start:] - self.test_value(len(models[7:]), 3) - self.test_value(models[7:][0].name(), '7') - self.test_value(models[7:][1].name(), '8') - self.test_value(models[7:][2].name(), '9') + # Return + return - # Test models[:end] - self.test_value(len(models[:2]), 2) - self.test_value(models[:2][0].name(), '0') - self.test_value(models[:2][1].name(), '1') + # Set test functions + def set(self): + """ + Set all test functions + """ + # Set test name + self.name('model') - # Test models[:] - self.test_value(len(models[:]), 10) - for i in range(10): - self.test_value(models[:][i].name(), '%s' % i) - - # Test models[start:end:step] - self.test_value(len(models[3:7:2]), 2) - self.test_value(models[3:7:2][0].name(), '3') - self.test_value(models[3:7:2][1].name(), '5') - - # Test models[start:end:step] - self.test_value(len(models[6:3:-2]), 2) - self.test_value(models[6:3:-2][0].name(), '6') - self.test_value(models[6:3:-2][1].name(), '4') - - # Test models[-start:] - self.test_value(len(models[-2:]), 2) - self.test_value(models[-2:][0].name(), '8') - self.test_value(models[-2:][1].name(), '9') - - # Test models[:-end] - self.test_value(len(models[:-7]), 3) - self.test_value(models[:-7][0].name(), '0') - self.test_value(models[:-7][1].name(), '1') - self.test_value(models[:-7][2].name(), '2') + # Append tests + self.append(self._test_models_access, 'Test GModels class model access') + self.append(self._test_models_slicing, 'Test GModels class slicing') # Return return diff --git a/test/test_GObservation.py b/test/test_GObservation.py index 6860c5a..d42b514 100755 --- a/test/test_GObservation.py +++ b/test/test_GObservation.py @@ -18,6 +18,7 @@ # # ========================================================================== import gammalib +import test_support # ========================================== # @@ -38,26 +39,39 @@ class Test(gammalib.GPythonTestSuite): # Return return - # Set test functions - def set(self): + # Setup GObservations container + def _setup_obs(self): """ - Set all test functions + Setup GObservations container + + Returns + ------- + obs : `~gammalib.GObservations` + Observation container """ - # Set test name - self.name('obs') + # Setup observation container + obs = gammalib.GObservations() + run = gammalib.GCTAObservation() + for i in range(10): + run.name('%s' % i) + run.id('%s' % i) + obs.append(run) - # Append tests - self.append(self.test_energy, 'Test GEnergy class') - self.append(self.test_energies, 'Test GEnergies class') - self.append(self.test_time, 'Test GTime class') - self.append(self.test_observations_slicing, - 'Test GObservations class slicing') + # Setup model container + models = gammalib.GModels() + model = gammalib.GModelSky() + for i in range(10): + model.name('%s' % i) + models.append(model) - # Return - return + # Set observation's model container + obs.models(models) + + # Return observations container + return obs # Test GEnergy class - def test_energy(self): + def _test_energy(self): """ Test GEnergy class """ @@ -131,7 +145,7 @@ class Test(gammalib.GPythonTestSuite): return # Test GEnergies class - def test_energies(self): + def _test_energies(self): """ Test GEnergies class """ @@ -149,7 +163,7 @@ class Test(gammalib.GPythonTestSuite): return # Test GTime class - def test_time(self): + def _test_time(self): """ Test GTime class """ @@ -217,78 +231,69 @@ class Test(gammalib.GPythonTestSuite): # Return return + # Test GObservations class access operators + def _test_observations_access(self): + """ + Test GObservations class observation access + """ + # Setup observation container and CTA observation + obs = self._setup_obs() + run = gammalib.GCTAObservation() + + # Perform observation access tests + test_support._container_access_index(self, obs) + + # Check observation setting by index from start + run.id('98') + obs[3] = run + self.test_value(obs[3].id(), '98') + + # Check observation setting by index from end + run.id('99') + obs[-2] = run + self.test_value(obs[-2].id(), '99') + + # Return + return # Test GObservations class slicing - def test_observations_slicing(self): + def _test_observations_slicing(self): """ Test GObservations class slicing """ # Setup observation container - obs = gammalib.GObservations() - run = gammalib.GCTAObservation() - for i in range(10): - run.id('%s' % i) - obs.append(run) + obs = self._setup_obs() - # Setup model container - models = gammalib.GModels() - model = gammalib.GModelSky() - for i in range(10): - model.name('%s' % i) - models.append(model) - - # Set observation's model container - obs.models(models) + # Perform slicing tests + test_support._container_slicing(self, obs) - # Test obs[start:end] - self.test_value(len(obs[3:5]), 2) + # Perform additional slicing tests self.test_value(len(obs[3:5].models()), 10) - self.test_value(obs[3:5][0].id(), '3') - self.test_value(obs[3:5][1].id(), '4') - - # Test obs[start:] - self.test_value(len(obs[7:]), 3) self.test_value(len(obs[7:].models()), 10) - self.test_value(obs[7:][0].id(), '7') - self.test_value(obs[7:][1].id(), '8') - self.test_value(obs[7:][2].id(), '9') - - # Test obs[:end] - self.test_value(len(obs[:2]), 2) self.test_value(len(obs[:2].models()), 10) - self.test_value(obs[:2][0].id(), '0') - self.test_value(obs[:2][1].id(), '1') - - # Test obs[:] - self.test_value(len(obs[:]), 10) self.test_value(len(obs[:].models()), 10) - for i in range(10): - self.test_value(obs[:][i].id(), '%s' % i) - - # Test obs[start:end:step] - self.test_value(len(obs[3:7:2]), 2) self.test_value(len(obs[3:7:2].models()), 10) - self.test_value(obs[3:7:2][0].id(), '3') - self.test_value(obs[3:7:2][1].id(), '5') - - # Test obs[start:end:step] - self.test_value(len(obs[6:3:-2]), 2) self.test_value(len(obs[6:3:-2].models()), 10) - self.test_value(obs[6:3:-2][0].id(), '6') - self.test_value(obs[6:3:-2][1].id(), '4') - - # Test obs[-start:] - self.test_value(len(obs[-2:]), 2) self.test_value(len(obs[-2:].models()), 10) - self.test_value(obs[-2:][0].id(), '8') - self.test_value(obs[-2:][1].id(), '9') - - # Test obs[:-end] - self.test_value(len(obs[:-7]), 3) self.test_value(len(obs[:-7].models()), 10) - self.test_value(obs[:-7][0].id(), '0') - self.test_value(obs[:-7][1].id(), '1') - self.test_value(obs[:-7][2].id(), '2') + + # Return + return + + # Set test functions + def set(self): + """ + Set all test functions + """ + # Set test name + self.name('obs') + + # Append tests + self.append(self._test_energy, 'Test GEnergy class') + self.append(self._test_energies, 'Test GEnergies class') + self.append(self._test_time, 'Test GTime class') + self.append(self._test_observations_access, 'Test GObservations class observation access') + self.append(self._test_observations_slicing, 'Test GObservations class slicing') # Return return diff --git a/test/test_support.py b/test/test_support.py new file mode 100755 index 0000000..f281fe4 --- /dev/null +++ b/test/test_support.py @@ -0,0 +1,114 @@ +# ========================================================================== +# This module provides support functions for the Python unit tests +# +# Copyright (C) 2017 Juergen Knoedlseder +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# ========================================================================== + + +# ============================== # +# Test container access by index # +# ============================== # +def _container_access_index(testsuite, container): + """ + Test container access by index + + Parameters + ---------- + testsuite : `~gammalib.GPythonTestSuite` + Test suite class + container : `~gammalib.GContainer` + Container class + """ + # Loop over all elements using the container iterator and count the number + # of iterations + niter = 0 + for element in container: + testsuite.test_value(element.name(), '%s' % niter) + niter += 1 + + # Check that looping was successful + testsuite.test_value(container.size(), 10, 'Check container size') + testsuite.test_value(niter, 10, 'Check container iterator') + + # Test access from start + testsuite.test_value(container[3].name(), '3') + + # Check access from end + testsuite.test_value(container[-2].name(), '8') + + # Return + return + + +# ====================== # +# Test container slicing # +# ====================== # +def _container_slicing(testsuite, container): + """ + Test container slicing + + Parameters + ---------- + testsuite : `~gammalib.GPythonTestSuite` + Test suite class + container : `~gammalib.GContainer` + Container class + """ + # Test container[start:end] + testsuite.test_value(len(container[3:5]), 2) + testsuite.test_value(container[3:5][0].name(), '3') + testsuite.test_value(container[3:5][1].name(), '4') + + # Test container[start:] + testsuite.test_value(len(container[7:]), 3) + testsuite.test_value(container[7:][0].name(), '7') + testsuite.test_value(container[7:][1].name(), '8') + testsuite.test_value(container[7:][2].name(), '9') + + # Test container[:end] + testsuite.test_value(len(container[:2]), 2) + testsuite.test_value(container[:2][0].name(), '0') + testsuite.test_value(container[:2][1].name(), '1') + + # Test container[:] + testsuite.test_value(len(container[:]), 10) + for i in range(10): + testsuite.test_value(container[:][i].name(), '%s' % i) + + # Test container[start:end:step] + testsuite.test_value(len(container[3:7:2]), 2) + testsuite.test_value(container[3:7:2][0].name(), '3') + testsuite.test_value(container[3:7:2][1].name(), '5') + + # Test container[start:end:step] + testsuite.test_value(len(container[6:3:-2]), 2) + testsuite.test_value(container[6:3:-2][0].name(), '6') + testsuite.test_value(container[6:3:-2][1].name(), '4') + + # Test container[-start:] + testsuite.test_value(len(container[-2:]), 2) + testsuite.test_value(container[-2:][0].name(), '8') + testsuite.test_value(container[-2:][1].name(), '9') + + # Test container[:-end] + testsuite.test_value(len(container[:-7]), 3) + testsuite.test_value(container[:-7][0].name(), '0') + testsuite.test_value(container[:-7][1].name(), '1') + testsuite.test_value(container[:-7][2].name(), '2') + + # Return + return