From 283a5c33c1ffee1226010bceda87836c3631351f Mon Sep 17 00:00:00 2001 From: Prasanth Nair Date: Fri, 3 Mar 2017 22:16:57 +0530 Subject: [PATCH 1/7] Porting to PY36: run import odespy made changes so that I can do "import odespy" at an IPython terminal without any errors. Changes made are in CHANGES_FOR_PY36.md. --- CHANGES_FOR_PY36.md | 47 ++++++++++++ odespy/RungeKutta.py | 41 +++++----- odespy/__init__.py | 25 +++--- odespy/odepack.py | 70 ++++++++--------- odespy/problems.py | 16 ++-- odespy/radau5.py | 12 +-- odespy/rkc.py | 10 +-- odespy/rkf45.py | 4 +- odespy/solvers.py | 179 ++++++++++++++++++++++--------------------- 9 files changed, 231 insertions(+), 173 deletions(-) create mode 100644 CHANGES_FOR_PY36.md diff --git a/CHANGES_FOR_PY36.md b/CHANGES_FOR_PY36.md new file mode 100644 index 0000000..5667d70 --- /dev/null +++ b/CHANGES_FOR_PY36.md @@ -0,0 +1,47 @@ +odespy/__init__.py + enable absolute imports , print function + use explicit relative imports + try statement around line that deletes variables from locals + +odespy/solvers.py + enable absolute imports , print function + replace all print statements with print function + Replaced many "ValueError, msg" to "ValueError(msg)" + Mixed spaces and tabs: lines 933-937, 962-967, 1508 + TypeError, msg to TypeError(msg): 1162 + ImportError, msg to ImportError(msg): 2014, 2944 + except Exception as e: 2993 + "not_valid is not defined error" at 2909 + apparently in Python 3 list comprehensions like this in class + body can't access variables defined in class body. This works in py2.7. + Replaced list comprehension with for loop. + in function _format_parameters_table: line 480, convert parameter_names + into list. dict.keys() in PY3 returns dict_list object not list. + +odespy/RungeKutta.py + enable absolute imports , print function + replace all print statements with print function + Replaced many "ValueError, msg" to "ValueError(msg)" + +odespy/rkc.py + enable absolute imports , print function + Replaced a few "ValueError, msg" to "ValueError(msg)" + +odespy/rkc.py + enable absolute imports , print function + replace all print statements with print function + +odespy/odepack.py + enable absolute imports , print function + Replaced a few "ValueError, msg" to "ValueError(msg)" + replace all print statements with print function + mixed tabs and space: 1203, 1232, 1235, 1343, 1456, 1574 + +odespy/radau5.py + enable absolute imports , print function + print function + tab/space: 283 + +odespy/problems.py + enable absolute imports , print function + print function diff --git a/odespy/RungeKutta.py b/odespy/RungeKutta.py index 73f99a1..41c8fe9 100644 --- a/odespy/RungeKutta.py +++ b/odespy/RungeKutta.py @@ -1,4 +1,5 @@ -from solvers import Solver, Adaptive +from __future__ import absolute_import, print_function +from . solvers import Solver, Adaptive import numpy as np def _calculate_order_1_level(coefficients): @@ -134,7 +135,7 @@ def middle(x,y,z): # Auxilary function k = np.zeros((k_len, self.neq), self.dtype) # intern stages if self.verbose > 0: - print 'advance solution in [%s, %s], h=%g' % (t_n, t_next, h) + print('advance solution in [%s, %s], h=%g' % (t_n, t_next, h)) # Loop until next time point is reached while (abs(t - t_n) < abs(t_next - t_n)): @@ -150,7 +151,7 @@ def middle(x,y,z): # Auxilary function self.info['rejected'] += 1 # reduced below if accepted if self.verbose > 0: - print ' u(t=%g)=%g: ' % (t+h, u_new), + print(' u(t=%g)=%g: ' % (t+h, u_new)), # local error between 2 levels error = h*np.abs(np.dot(factors_error, k)) @@ -171,18 +172,18 @@ def middle(x,y,z): # Auxilary function self.info['rejected'] -= 1 if self.verbose > 0: - print 'accepted, ', + print('accepted, '), else: if self.verbose > 0: - print 'rejected, ', + print('rejected, '), if self.verbose > 0: - print 'err=%s, ' % str(error), + print('err=%s, ' % str(error)), if hasattr(self, 'u_exact') and callable(self.u_exact): - print 'exact-err=%s, ' % \ - (np.asarray(self.u_exact(t+h))-u_new), + print('exact-err=%s, ' % + (np.asarray(self.u_exact(t+h))-u_new)), if h <= self.min_step: - print 'h=min_step!! ', + print('h=min_step!! '), # Replace 0 values by 1e-16 since we will divide by error @@ -209,7 +210,7 @@ def middle(x,y,z): # Auxilary function h = min(h, t_next - t_intermediate[-1]) if self.verbose > 0: - print 'new h=%g' % h + print('new h=%g' % h) if h == 0: break @@ -367,16 +368,16 @@ def validate_data(self): # Check for dimension of user-defined butcher table. array_shape = self.butcher_tableau.shape if len(array_shape) is not 2: - raise ValueError,''' - Illegal input! Your input butcher_tableau should be a 2d-array!''' + raise ValueError(''' + Illegal input! Your input butcher_tableau should be a 2d-array!''') else: m,n = array_shape if m not in (n, n + 1): - raise ValueError, '''\ + raise ValueError('''\ The dimension of 2d-array should be: 1. Either (n, n), --> For 1-level RungeKutta methods 2. Or (n+1, n), --> For 2-levels RungeKutta methods - The shape of your input array is (%d, %d).''' % (m,n) + The shape of your input array is (%d, %d).''' % (m,n)) self._butcher_tableau = self.butcher_tableau # Check for user-defined order, @@ -393,19 +394,19 @@ def validate_data(self): if array_shape[0] == array_shape[1] + 1: # 2-level RungeKutta methods if type(self.method_order) is int: - raise ValueError, error_2level + raise ValueError(error_2level) try: order1, order2 = self.method_order if abs(order1-order2) != 1 or \ order1 < 1 or order2 < 1: - raise ValueError, error_2level + raise ValueError(error_2level) except: - raise ValueError,error_2level + raise ValueError(error_2level) else: # 1-level RungeKutta methods if type(self.method_order) is not int or \ self.method_order < 1: - raise ValueError,error_1level + raise ValueError(error_1level) self._method_order = self.method_order else: # method_order is not specified @@ -418,7 +419,7 @@ def validate_data(self): for i in range(1,array_shape[1] - 1): if not np.allclose(self.butcher_tableau[i][0],\ sum(self.butcher_tableau[i][1:])): - raise ValueError, ''' + raise ValueError(''' Inconsistent data in Butcher_Tableau! In each lines of stage-coefficients, first number should be equal to the sum of other numbers. @@ -426,6 +427,6 @@ def validate_data(self): a[i][0] == a[i][1] + a[i][2] + ... + a[i][K - 1] where 1 <= i <= K - 1 Your input for line %d is :%s - ''' % (i,str(self.butcher_tableau[i])) + ''' % (i,str(self.butcher_tableau[i]))) return True diff --git a/odespy/__init__.py b/odespy/__init__.py index 9212728..4b92993 100644 --- a/odespy/__init__.py +++ b/odespy/__init__.py @@ -5,6 +5,7 @@ supported. A wide range of numerical methods for ODEs are offered: """ +from __future__ import absolute_import, print_function # Insert tutorial from ../doc/src/odespy/odespy.rst @@ -1254,14 +1255,13 @@ def f(u, t): The file `logistic10.py `_ contains a complete program for solving the logistic ODE with :math:`f(u,t)` implemented in Fortran. ''' - -from solvers import * -from RungeKutta import * -from rkc import * -from rkf45 import * -from odepack import * -from radau5 import * -import problems +from . solvers import * +from . RungeKutta import * +from . rkc import * +from . rkf45 import * +from . odepack import * +from . radau5 import * +from . import problems # Update doc strings with common info class_, doc_str, classname = None, None, None @@ -1282,8 +1282,13 @@ def f(u, t): __doc__ = __doc__ + typeset_toc(toc) + _tutorial # Do not pollute namespace -del class_, doc_str, classname, classnames, toc, typeset_toc, \ - table_of_parameters, name, obj, inspect +try: + del class_, doc_str, classname, classnames, toc, typeset_toc, \ + table_of_parameters, name, obj, inspect +except NameError: + # the var 'name' is used in a list compression, which is leaked into + # locals in PY2 but not in Py3 (at-least py3.6). + pass if __name__ == '__main__': from os.path import join diff --git a/odespy/odepack.py b/odespy/odepack.py index 96523c6..f615319 100644 --- a/odespy/odepack.py +++ b/odespy/odepack.py @@ -1,9 +1,9 @@ -__author__ = ['Liwei Wang, Univ. of Oslo'] - -from solvers import Solver +from __future__ import absolute_import, print_function +from . solvers import Solver import numpy as np import sys, inspect +__author__ = ['Liwei Wang, Univ. of Oslo'] _parameters_Odepack = dict( # Note that ODEPACK has its own convention for the @@ -463,7 +463,7 @@ ) -import solvers +from . import solvers solvers._parameters.update(_parameters_Odepack) @@ -735,9 +735,9 @@ def check_liwlrw(self): else: value = getattr(self, name) if value < min_value: - print ''' + print(''' Insufficient input! "%s"=%d are reset to be the minimum size = %d '''\ - % (name, value, min_value) + % (name, value, min_value)) setattr(self, name, min_value) def check_tol(self): @@ -759,8 +759,8 @@ def check_pars(self): for pars in (('ia', 'ja'), ('ic', 'jc'), ('ml', 'mu'), ('mb', 'nb')): arg_a, arg_b = pars if int(hasattr(self, arg_a) + hasattr(self, arg_b)) == 1: - raise ValueError,'\ - Error! %s and %s have to be input simutaneously!' % (arg_a, arg_b) + raise ValueError('\ + Error! %s and %s have to be input simutaneously!' % (arg_a, arg_b)) def check_iaja(self): ''' @@ -797,7 +797,7 @@ def check_iaja(self): array_a[-1] != len(array_b)+1) for error_index in range(3): if iaja_check[error_index]: - raise ValueError, err_messages[error_index] + raise ValueError(err_messages[error_index]) def validate_data(self): ''' @@ -945,17 +945,17 @@ def new_stepnr(self): ''' nsteps = getattr(self, 'nsteps', 500) if nsteps == 2000: # The maximum step-amount has been reached - raise ValueError, ''' + raise ValueError(''' Failed iteration although step number has been set to 2000. - Please check your input.''' + Please check your input.''') mx_new = min(nsteps+200, 2000) # maximum limitation is set to 2000 self.nsteps = mx_new # valid for the following steps - print '''\ + print('''\ Excessive amount of work detected! Input step amount "nsteps"=%d is not enough for iteration! nsteps has been reset to %d to avoid this error!'''\ - % (nsteps, mx_new) + % (nsteps, mx_new)) return mx_new def tol_multiply(self, tolsf): @@ -966,7 +966,7 @@ def tol_multiply(self, tolsf): Then we could try to adjust tolerance settings with suggested factor to avoid this error. ''' - print 'Tolerance is scaled by suggested factor %.2g''' % tolsf + print('Tolerance is scaled by suggested factor %.2g''' % tolsf) self.rtol *= tolsf self.atol *= tolsf @@ -975,7 +975,7 @@ def expand_rwork(self, new_lrw, expand=False): Length of real work array is smaller than actually required length. Then we could expand work array to avoid this error. ''' - print 'The length of real work array has been reset to %d' % new_lrw + print('The length of real work array has been reset to %d' % new_lrw) if expand: # Expand real arrays for linearly implicit solvers self.rwork = list(self.rwork) + [0.]*(new_lrw-self.lrw) self.lrw = new_lrw @@ -986,7 +986,7 @@ def expand_iwork(self, new_liw, expand=False): integer work array when it is too short. Then we could expand work array to required length to avoid this error. ''' - print 'The length of integer work array has been reset to %d' % new_liw + print('The length of integer work array has been reset to %d' % new_liw) if expand: # Expand integer arrays for linearly implicit solvers self.iwork = list(self.iwork) + [0.]*(new_liw - self.liw) self.liw = new_liw @@ -1023,11 +1023,11 @@ def print_roots(self, jroot, t_current, u_current): value = g(t_current, u_current) for i in range(ng): if jroot[i]: # found root for i-th constraint equation - print ''' + print(''' Root found at t = %g for %dth constraint function in g''' \ - % (t_current, i+1) + % (t_current, i+1)) value_ith = value[i] if ng > 1 else value - print 'Error in location of root is %g' % value_ith + print('Error in location of root is %g' % value_ith) def solve(self, time_points, terminate=None): @@ -1087,11 +1087,11 @@ def solve(self, time_points, terminate=None): self.finished = True tried = 0 elif istate == 0: - print "Iteration stops at step Nr.%d," % nstop - print " when function TERMINATE return with True." + print("Iteration stops at step Nr.%d," % nstop) + print(" when function TERMINATE return with True.") self.finished = True elif istate < 0: # Error occurs! - print self._error_messages[istate] + str(rinfo[1]) + print(self._error_messages[istate] + str(rinfo[1])) if istate == -1: # Increase maximum step-number. self.iwork_in[5] = self.new_stepnr() self.iopt = 1 @@ -1175,12 +1175,12 @@ def advance(self): self.rwork, self.lrw, self.iwork, self.liw, self.mf), self._extra_args_fortran) tried += 1 - # "istate" indicates the returned status + # "istate" indicates the returned status if istate >= 1: # successful return status break else: # Error occurs! - print self._error_messages[istate] + str(self.rwork[12]) + print(self._error_messages[istate] + str(self.rwork[12])) if istate == -1: # Increase maximum step-number. self.iwork[5], self.iopt = self.new_stepnr(), 1 elif istate == -2: # Multiply tolerance with suggested factor @@ -1200,7 +1200,7 @@ def advance(self): else: # Unavoidable interrupts sys.exit(1) # Interrupt istate = 1 - return u_new + return u_new ### end of class Odepack ### @@ -1229,8 +1229,8 @@ class Lsode(Odepack): _extra_args_fortran = {} def adjust_parameters(self): - """Properties for new parameters in this solver.""" - # If jac_banded is input in form of jac(u,t,ml,mu), + """Properties for new parameters in this solver.""" + # If jac_banded is input in form of jac(u,t,ml,mu), # wrap jac_banded to jac_banded_f77 for Fortran code self._parameters['jac_banded']['paralist_old'] = 'u,t,ml,mu' self._parameters['jac_banded']['paralist_new'] = 't,u,ml,mu' @@ -1340,7 +1340,7 @@ class Lsoda(Odepack): was successful as far as ''' def adjust_parameters(self): - """Properties for new parameters in this solver.""" + """Properties for new parameters in this solver.""" # If jac_banded is input in form of jac(u,t,ml,mu), # wrap jac_banded to jac_banded_f77 for Fortran code self._parameters['jac_banded']['paralist_old'] = 'u,t,ml,mu' @@ -1453,7 +1453,7 @@ class Lsodar(Odepack): was successful as far as ''' def adjust_parameters(self): - """Properties for new parameters in this solver.""" + """Properties for new parameters in this solver.""" # If jac_banded is input in form of jac(u,t,ml,mu), # wrap jac_banded to jac_banded_f77 for Fortran code self._parameters['jac_banded']['paralist_old'] = 'u,t,ml,mu' @@ -1541,9 +1541,9 @@ def solve(self, time_points, terminate=None): if not hasattr(self.g_f77,'_cpointer'): self.ng = np.asarray(self.g(time_points[0],self.U0)).size elif not hasattr(self,'ng'): - raise ValueError, ''' + raise ValueError(''' Unsufficient input! ng must be specified if g is input as a - Fortran subroutine. ''' + Fortran subroutine. ''') return Odepack.solve(self,time_points, terminate=terminate) ### End of Lsodar ### @@ -1571,7 +1571,7 @@ class Lsodes(Odepack): def adjust_parameters(self): - """Properties for new parameters in this solver.""" + """Properties for new parameters in this solver.""" # If jac_column is input in form of jac(u,t,j), # wrap jac_column to jac_column_f77(t,u,j-1) for Fortran code. self._parameters['jac_column']['paralist_old'] = 'u,t,j-1,ia,ja' @@ -1777,7 +1777,7 @@ def set_iter_method(self): elif with_full_adda: self.iter_method = 2 else: - raise ValueError, 'adda must be supplied in Lsodi.' + raise ValueError('adda must be supplied in Lsodi.') def set_jac(self): if self.iter_method == 4: @@ -2072,9 +2072,9 @@ def validate_data(self): if not Odepack.validate_data(self): return False if self.mb*self.nb != self.neq: - raise ValueError,''' + raise ValueError(''' The requirement for block size (mb,nb) are: mb>=1, nb>=4, mb*nb=neq=%d. - Your block size are (%d,%d). ''' % (self.neq, mb, nb) + Your block size are (%d,%d). ''' % (self.neq, mb, nb)) return True def solve(self, time_points, terminate=None): diff --git a/odespy/problems.py b/odespy/problems.py index 023e218..e797300 100644 --- a/odespy/problems.py +++ b/odespy/problems.py @@ -1,5 +1,7 @@ +from __future__ import absolute_import, print_function import numpy as np -from solvers import compile_f77 +from . solvers import compile_f77 + class Problem: ''' @@ -282,7 +284,7 @@ def u_exact(self, t): def default_oscillator(P, resolution_per_period=20): n = 4.5 r = resolution_per_period # short form - print 'default', P, n*P + print('default', P, n*P) tp = np.linspace(0, n*P, r*n+1) # atol=rtol since u approx 1, atol level set at the # error RK4 produces with 20 steps per period, times 0.05 @@ -519,7 +521,7 @@ def tester(problems, methods, time_points=None, compare_tol=1E-4, error_msg = {} for problem in problems: pname = problem.__class__.__name__ - print 'problem ', pname + print('problem ', pname) methods4problem = [method for method in methods if method not in problem.not_suitable_solvers] defaults = problem.default_parameters() @@ -541,7 +543,7 @@ def tester(problems, methods, time_points=None, compare_tol=1E-4, this_solver_prm[name] = defaults[name] for method in methods4problem: - print ' testing', method, + print(' testing', method) solver = eval('odespy.'+method)(problem.f) # Important to set parameters before setting initial cond. @@ -554,12 +556,12 @@ def tester(problems, methods, time_points=None, compare_tol=1E-4, error = problem.verify(u, t) if error is not None: results[pname][method] = (u, error) - print error, + print(error) if error > compare_tol: - print 'WARNING: tolerance %.0E exceeded' % compare_tol, + print('WARNING: tolerance %.0E exceeded' % compare_tol) else: results[pname][method] = (u,) - print + print() return results """ diff --git a/odespy/radau5.py b/odespy/radau5.py index f185888..522b64e 100644 --- a/odespy/radau5.py +++ b/odespy/radau5.py @@ -1,9 +1,9 @@ -__author__ = ['Liwei Wang, Univ. of Oslo'] - -from odespy import Solver +from __future__ import absolute_import, print_function +from . import Solver import numpy as np import sys +__author__ = ['Liwei Wang, Univ. of Oslo'] _parameters_Radau5 = dict( mas = dict( @@ -80,7 +80,7 @@ type=callable), ) -import solvers +from . import solvers solvers._parameters.update(_parameters_Radau5) @@ -278,9 +278,9 @@ def advance(self): *args, **self._extra_args_fortran) if idid < 0: # Error occurred - print self._error_messages[idid] + str(t_new) + print(self._error_messages[idid] + str(t_new)) sys.exit(1) # Interrupt - return u_new + return u_new ### end of class Radau5 ### diff --git a/odespy/rkc.py b/odespy/rkc.py index 92fb753..7ca2ae5 100644 --- a/odespy/rkc.py +++ b/odespy/rkc.py @@ -1,6 +1,6 @@ """Module for wrapping rkc.f.""" - -from solvers import Solver, Adaptive +from __future__ import absolute_import, print_function +from . solvers import Solver, Adaptive import numpy as np # f_f77 and other items are defined in odepack.py and will @@ -31,7 +31,7 @@ type=callable), ) -import solvers +from . import solvers solvers._parameters.update(_parameters_RKC) class RKC(Adaptive): @@ -105,9 +105,9 @@ def check_atol(self): atol = self.atol if not isinstance(atol,float): if len(atol) not in (1, self.neq): - raise ValueError, ''' + raise ValueError(''' ATOL =%s should be either a scalar or a vector of length NEQ=%d. - ''' % (str(atol), self.neq) + ''' % (str(atol), self.neq)) def validate_data(self): self.check_atol() diff --git a/odespy/rkf45.py b/odespy/rkf45.py index 486ca30..b526d5a 100644 --- a/odespy/rkf45.py +++ b/odespy/rkf45.py @@ -1,6 +1,6 @@ """Module for wrapping rkf45.py.""" - -from solvers import Solver, Adaptive +from __future__ import absolute_import, print_function +from . solvers import Solver, Adaptive import numpy as np diff --git a/odespy/solvers.py b/odespy/solvers.py index af595d4..82cf018 100644 --- a/odespy/solvers.py +++ b/odespy/solvers.py @@ -1,5 +1,5 @@ # Authors: Liwei Wang, Hans Petter Langtangen - +from __future__ import absolute_import, print_function ''' This module contains the base class ``Solver`` package and the implementations of many subclasses. @@ -477,7 +477,7 @@ def _format_parameters_table(parameter_names, fixed_width=None): if fixed_width is None: max_name_length = max([len(name) \ - for name in parameter_names + ['Name']]) + for name in list(parameter_names) + ['Name']]) c1 = max_name_length + 1 # width of column 1 c2 = (max_line_width - c1) # width of column 2 else: @@ -521,8 +521,8 @@ def table_of_parameters(classname): opt_prm = getattr(classname, '_optional_parameters') for name in opt_prm: if not name in _parameters: - print 'Parameter "%s" used in class %s is not registered in _parameters.' % (name, classname.__name__) - print 'Do that before proceeding.' + print('Parameter "%s" used in class %s is not registered in _parameters.' % (name, classname.__name__)) + print('Do that before proceeding.') sys.exit(1) s = """ @@ -696,10 +696,9 @@ def compile_string_functions(self, f, **kwargs): else: kwargs[func] = getattr(_callback,func) except: - raise ValueError, ''' - F2py failed to compile input string (=\n%s) - to be callable functions (%s).''' \ - % (string_to_compile, str_funcs.keys()) + raise ValueError(''' + F2py failed to compile input string (=\n%s) + to be callable functions (%s).''' % (string_to_compile, str_funcs.keys())) return f, kwargs def adjust_parameters(self): @@ -859,13 +858,13 @@ def check_extra(self, **kwargs): for name, check_funcs, value in prm_type_list: try: if not check_funcs(value): # Return false - raise ValueError,''' + raise ValueError(''' Improper value (=%s) for parameter %s. - Please check your input.''' % (str(value), name) + Please check your input.''' % (str(value), name)) except: # cannot run check_function smoothly - raise ValueError,''' + raise ValueError(''' Cannot run check function for %s=%s. - Please check your input.''' % (name, str(value)) + Please check your input.''' % (name, str(value))) return True def get(self, parameter_name=None, print_info=False): @@ -889,14 +888,14 @@ def get(self, parameter_name=None, print_info=False): all_args['name of jac'] = self.users_jac.func_name if print_info: - print pprint.pformat(all_args) + print(pprint.pformat(all_args)) return all_args else: if hasattr(self, parameter_name): value = getattr(self, parameter_name) if print_info: - print "%s = %s" % (parameter_name, value) + print("%s = %s" % (parameter_name, value)) return value else: raise AttributeError('Parameter %s is not set' % parameter_name) @@ -907,12 +906,12 @@ def get_parameter_info(self,print_info=False): legal parameters in current subclass (i.e., the parameters in ``self._parameters``). - If *print_info* is *True*, the ``self._parameters`` dict + If *print_info* is *True*, the ``self._parameters`` dict) is pretty printed, otherwise it is returned. ''' if print_info: - print 'Legal parameters for class %s are:' % self.__class__.__name__ - print pprint.pformat(self._parameters) + print('Legal parameters for class %s are:' % self.__class__.__name__) + print(pprint.pformat(self._parameters)) return None else: return self._parameters @@ -931,11 +930,11 @@ def _print_method(self, with_f, default): if with_f and hasattr(self, 'users_f'): if not hasattr(self.users_f, '__name__'): # class instance? f_name = self.users_f.__class__.__name__ - else: # Ordinary functions - f_name = self.users_f.__name__ - if f_name == '': # lambda function - f_name = 'lambda u, t: ...' - args.append('f=%s' % f_name) + else: # Ordinary functions + f_name = self.users_f.__name__ + if f_name == '': # lambda function + f_name = 'lambda u, t: ...' + args.append('f=%s' % f_name) # form all parameters for name in self._parameters: @@ -960,14 +959,13 @@ def _print_method(self, with_f, default): if hasattr(self, 'users_jac'): if hasattr(self.users_jac, '__name__'): # plain function? f_name = self.users_jac.__name__ - if f_name == '': # lambda function - #f_name = 'lambda u, t: ...' - f_name = 'lambda' - else: # class instance + if f_name == '': # lambda function + # f_name = 'lambda u, t: ...' + f_name = 'lambda' + else: # class instance f_name = self.users_jac.__class__.__name__ args.append('jac=%s' % f_name) - args = ', '.join(args) if args: s += '(%s)' % args @@ -1045,11 +1043,11 @@ def solve(self, time_points, terminate=None): self.u[n+1] = self.advance() # new value if self.verbose > 2: - print '%s, step %d, t=%g' % \ - (self.__class__.__name__, n+1, self.t[n+1]) + print('%s, step %d, t=%g' % + (self.__class__.__name__, n+1, self.t[n+1])) if terminate(self.u, self.t, n+1): - print self.__class__.__name__, \ - 'terminated at t=%g' % self.t[n+1] + print(self.__class__.__name__, + 'terminated at t=%g' % self.t[n+1]) if not self.disk_storage: self.u, self.t = self.u[:n+2], self.t[:n+2] # else: must keep original size of file, rest is 0 @@ -1084,7 +1082,7 @@ def initialize_for_solve(self): if len(self.t) < 2: raise ValueError('time_points array %s must have at least two elements' % repr(self.t)) if self.verbose > 0: - print 'Calling f(U0, %g) to determine data type' % self.t[0] + print('Calling f(U0, %g) to determine data type' % self.t[0]) value = np.array(self.f(self.U0, self.t[0])) else: value = np.asarray(self.U0) @@ -1161,23 +1159,23 @@ def validate_data(self): or (not np.asarray( # all items in self.t should be numbers [isinstance(t, (int,float)) for t in self.t]).all()): - raise TypeError, \ - 'solve: time_points(=%s) is not a proper '\ - 'sequence of real numbers' % str(self.t) + raise TypeError( + 'solve: time_points(=%s) is not a proper ' + 'sequence of real numbers' % str(self.t)) # self.t should be supplied in an asscending/descending order t_sorted = sorted(self.t, reverse=self.t[0] > self.t[-1]) if list(self.t) != list(t_sorted): - raise ValueError, \ - 'time_points(=%s) is not provided in an ascending/descending'\ - ' order!' % str(self.t) + raise ValueError( + 'time_points(=%s) is not provided in an ascending/descending' + ' order!' % str(self.t)) # Test whether all required parameters are provided for arg in self._required_parameters: if not hasattr(self, arg): - raise ValueError,\ - '"%s" has to be input as required parameter(s) for '\ - 'solver %s.' % (arg,self.__class__.__name__) + raise ValueError( + '"%s" has to be input as required parameter(s) for ' + 'solver %s.' % (arg,self.__class__.__name__)) return True def switch_to(self, solver_target, print_info=False, **kwargs): @@ -1200,11 +1198,11 @@ def switch_to(self, solver_target, print_info=False, **kwargs): >>> m1 = odespy.RK2(f) >>> m1.set_initial_condition(1.) >>> u1, t = m1.solve(time_points) - >>> print 'Normarized error with RK2 is %g' % np.linalg.norm(u1 - exact_u) + >>> print('Normarized error with RK2 is %g' % np.linalg.norm(u1 - exact_u)) Normarized error with RK2 is 0.0077317 >>> m2 = m1.switch_to(odespy.RKFehlberg, rtol=1e-18) >>> u2, t = m2.solve(time_points) - >>> print 'Normarized error with RKFehlberg is %g' % np.linalg.norm(u2 - exact_u) + >>> print('Normarized error with RKFehlberg is %g' % np.linalg.norm(u2 - exact_u)) Normarized error with RKFehlberg is 8.55517e-08 """ # Extract name list of all the subclasses in this module @@ -1220,10 +1218,10 @@ def switch_to(self, solver_target, print_info=False, **kwargs): # Convert string to class name solver_target = getattr(odespy, solver_target) except: - raise ValueError, error_message + raise ValueError(error_message) if not solver_target.__name__ in list_all_solvers(): - raise ValueError, error_message + raise ValueError(error_message) @@ -1266,9 +1264,9 @@ def switch_to(self, solver_target, print_info=False, **kwargs): diff_args = set(self.__dict__.keys()) - set(new.__dict__.keys()) \ - set(('u','t','n','dtype')) if diff_args: - print 'These attributes are neglected in %s: %s\n' \ - % (solver_target.__name__, str(diff_args)[5:-2]) - print 'Switched to solver %s' % str(solver_target.__name__) + print('These attributes are neglected in %s: %s\n' \ + % (solver_target.__name__, str(diff_args)[5:-2])) + print('Switched to solver %s' % str(solver_target.__name__)) return new @@ -1329,14 +1327,14 @@ def check_conditional_parameters(self): # Either 'jac' or 'jac_f77' should be supplied found = bool([p_name for p_name in arg \ if hasattr(self,p_name)]) - arg_print = 'One of %s' % str(arg) + arg_print= 'One of %s' % str(arg) else: # arg is a single parameter found = hasattr(self, arg) - arg_print = arg + arg_print= arg if not found: - raise ValueError,'''\ + raise ValueError('''\ Error! Unsufficient input! - %s must be set when %s is %s!''' % (arg_print,name,value) + %s must be set when %s is %s!''' % (arg_print,name,value)) return True def has_u_t_all(self): @@ -1507,7 +1505,7 @@ def advance(self): dt = t[n+1] - t[n] K1 = dt*f(u[n], t[n]) K2 = dt*f(u[n] + 0.5*K1, t[n] + 0.5*dt) - u_new = u[n] + K2 + u_new = u[n] + K2 return u_new @@ -1587,7 +1585,7 @@ def initialize_for_solve(self): def validate_data(self): """Check that the time steps are constant.""" if not self.constant_time_step(): - print '%s must have constant time step' % self.__name__ + print('%s must have constant time step' % self.__name__) return False else: return True @@ -1636,7 +1634,7 @@ def initialize_for_solve(self): def validate_data(self): if not self.constant_time_step(): - print '%s must have constant time step' % self.__name__ + print('%s must have constant time step' % self.__name__) return False else: return True @@ -1689,7 +1687,7 @@ def initialize_for_solve(self): def validate_data(self): if not self.constant_time_step(): - print '%s must have constant time step' % self.__name__ + print('%s must have constant time step' % self.__name__) return False else: return True @@ -1743,7 +1741,7 @@ def initialize_for_solve(self): def validate_data(self): if not self.constant_time_step(): - print '%s must have constant time step' % self.__name__ + print('%s must have constant time step' % self.__name__) return False else: return True @@ -1800,7 +1798,7 @@ def initialize_for_solve(self): def validate_data(self): if not self.constant_time_step(): - print '%s must have constant time step' % self.__name__ + print('%s must have constant time step' % self.__name__) return False else: return True @@ -2013,7 +2011,7 @@ def initialize(self): import sympy self.sympy = sympy except ImportError: - raise ImportError,'sympy is not installed - needed for sympy_odefun' + raise ImportError('sympy is not installed - needed for sympy_odefun') def initialize_for_solve(self): # sympy.odefun requires f(t, u), not f(u, t, *args, **kwargs) @@ -2119,8 +2117,8 @@ def advance(self): u_new = un + (t_new-tn)*f(un,tn) # control by number of intern steps and error tolerance if self.verbose > 1: - print '%s.advance w/%s: t=%g, n=%d: ' % \ - (self.__class__.__name__, self.nonlinear_solver, t_new, n+1), + print('%s.advance w/%s: t=%g, n=%d: ' % \ + (self.__class__.__name__, self.nonlinear_solver, t_new, n+1)), while i <= self.max_iter and error > self.eps_iter: if self.nonlinear_solver == 'Linear': @@ -2140,11 +2138,11 @@ def advance(self): r = self.relaxation # relaxation factor u_new = r*u_new_ + (1-r)*un if self.verbose > 2: - print ' u_%02d=%g (err=%g)' % (i, u_new, error) + print(' u_%02d=%g (err=%g)' % (i, u_new, error)) i += 1 self.num_iterations_total += i-1 if self.verbose > 1: - print ' u=%g in %d iterations' % (u_new, i-1) + print(' u=%g in %d iterations' % (u_new, i-1)) if error > self.eps_iter: raise ValueError('%s w/%s not converged:\n difference in solution between last two iterations: %g > eps_iter=%g after %s iterations.' % (self.__class__.__name__, self.nonlinear_solver, error, self.eps_iter, self.max_iter)) return u_new @@ -2407,13 +2405,13 @@ def solve(self, time_points, terminate=None): time_points = np.linspace(t[k-1], t[k], ntpoints+1) dt = time_points[1] - time_points[0] if self.verbose > 0: - print 'dt=%g, ' % dt, + print('dt=%g, ' % dt,) if dt < self.min_step and self.verbose > 0: - print 'too small %s < %s, ' % (dt, self.min_step) - print + print('too small %s < %s, ' % (dt, self.min_step)) + print() break if dt > self.max_step and self.verbose > 0: - print 'too large %s > %s, ' % (dt, self.max_step) + print('too large %s > %s, ' % (dt, self.max_step)) break self.solver.set_initial_condition(self.u[-1]) @@ -2421,10 +2419,10 @@ def solve(self, time_points, terminate=None): #R = self.residual(u_new[-2], u_new[-1], t_new[-2], t_new[-1]) R = self.residual(u_new[0], u_new[-1], t_new[0], t_new[-1]) if self.verbose > 0: - print '\n%d time points in (t[%d], t[%d]) = (%.3g, %.3g), ' \ - % (ntpoints+1, k-1, k, t[k-1], t[k]) - print 'Residual=%.1E, tolerance=%.1E, calling %s' % \ - (R, self.atol, self.solver.__class__.__name__) + print('\n%d time points in (t[%d], t[%d]) = (%.3g, %.3g), ' + % (ntpoints+1, k-1, k, t[k-1], t[k])) + print('Residual=%.1E, tolerance=%.1E, calling %s' % \ + (R, self.atol, self.solver.__class__.__name__)) # reintegrate with time_step = dt/2 ntpoints *= 2 self.u.extend(u_new[1:]) @@ -2511,8 +2509,8 @@ def middle(x, y, z): self.h = first_step if self.verbose: - print '\nadvance solution in [%g, %g], ' % (t, t_np1), - print 'starting with h=%g' % self.h + print('\nadvance solution in [%g, %g], ' % (t, t_np1),) + print('starting with h=%g' % self.h) while t < t_np1: @@ -2521,7 +2519,7 @@ def middle(x, y, z): u_new, error = self.advance_intermediate(u, t, self.h) if self.verbose: - print 'u(t=%g): %g, ' % (t + self.h, u_new), + print('u(t=%g): %g, ' % (t + self.h, u_new),) # Is u_new sufficiently accurate? u_new_norm = np.linalg.norm(u_new) @@ -2537,24 +2535,24 @@ def middle(x, y, z): if self.verbose: if sufficiently_accurate: - print 'accepted, ', + print('accepted, ',) else: - print 'rejected, ', - print ' err=%g (tol=%.1E), ' % (error, tol), + print('rejected, ',) + print(' err=%g (tol=%.1E), ' % (error, tol),) if hasattr(self, 'u_exact'): - print 'exact-err: %g, ' % \ - (np.abs(np.asarray(self.u_exact(t))-u)), + print('exact-err: %g, ' % + (np.abs(np.asarray(self.u_exact(t))-u))), # Adjust time step if error > 1E-14: h_new = self.h*(tol/error)**(1./self.order) - print 'changing time step', h_new, min_step, max_step + print('changing time step', h_new, min_step, max_step) self.h = middle(min_step, h_new, max_step) self.h = min(self.h, t_np1-t) # fit last step if self.verbose: - print 'new h=%g' % self.h + print('new h=%g' % self.h) return u @@ -2727,7 +2725,7 @@ def advance(self): u, f, n, t = self.u, self.f, self.n, self.t u_new = self.integrator.integrate(t[n+1]) if not self.integrator.successful(): - print 'Warning: %s call to ode.method.integrate in scipy.integrate was not successful' % self.__class__.__name__ + print('Warning: %s call to ode.method.integrate in scipy.integrate was not successful' % self.__class__.__name__) if len(u_new) == 1: return u_new[0] else: @@ -2908,7 +2906,12 @@ class odelab(Adaptive): solvers = 'ExplicitEuler ExplicitTrapezoidal ImplicitEuler RungeKutta34 RungeKutta4 SymplecticEuler ImplicitEuler LDIRK343 LobattoIIIA LobattoIIIB LobattoIIIC LobattoIIICs LobattoIIID MultiRKDAE RKDAE RadauIIA RungeKutta Spark Spark2 Spark3 Spark4 AdamsBashforth AdamsBashforth1 AdamsBashforth2 AdamsBashforth2e Butcher Butcher1 Butcher3 ExplicitGeneralLinear GeneralLinear Heun Kutta Kutta38 Kutta4 McLachlan NonHolonomicEnergy NonHolonomicEnergy0 NonHolonomicEnergyEMP NonHolonomicLeapFrog SymplecticEuler ABLawson ABLawson2 ABLawson3 ABLawson4 ABNorset4 Exponential GenLawson45 HochOst4 Lawson4 LawsonEuler Phi Polynomial RKMK4T'.split() DAE_solvers = 'SymplicticEuler MultiRKDAE RKDAE Spark Spark2 Spark3 Spark4'.split() not_valid = 'SymplecticEuler LDIRK343 LobattoIIIA LobattoIIIB LobattoIIIC LobattoIIICs LobattoIIID MultiRKDAE RKDAE RadauIIA RungeKutta Spark Spark2 Spark3 Spark4 AdamsBashforth AdamsBashforth2 AdamsBashforth2e Butcher Butcher1 Butcher3 ExplicitGeneralLinear GeneralLinear Kutta McLachlan NonHolonomicEnergy NonHolonomicEnergy0 NonHolonomicEnergyEMP NonHolonomicLeapFrog SymplecticEuler ABLawson ABLawson2 ABLawson3 ABLawson4 ABNorset4 Exponential GenLawson45 HochOst4 Lawson4 LawsonEuler Phi Polynomial RKMK4T'.split() - solvers = [solver for solver in solvers if not solver in not_valid] + # solvers = [solver for solver in solvers if not solver in not_valid] + solvers_tmp = [] + for solver in solvers: + if solver not in not_valid: + solvers_tmp.append(solver) + solvers = solvers_tmp __doc__ = __doc__ % (str(solvers)[1:-1]) @@ -2943,7 +2946,7 @@ def initialize(self): self.odelab_schemes = schemes except ImportError: - raise ImportError,'The odelab software is not installed - needed for class odelab' + raise ImportError('The odelab software is not installed - needed for class odelab') def initialize_for_solve(self): # odelab requires f(t, u), not f(u, t, *args, **kwargs) @@ -2979,7 +2982,7 @@ def solve(self, time_points, terminate=None): since odelab. is such a solve method. """ if terminate is not None: - print 'Warning: odelab.solve ignores the terminate function!' + print('Warning: odelab.solve ignores the terminate function!') self.t = np.asarray(time_points) try: @@ -2992,11 +2995,11 @@ def solve(self, time_points, terminate=None): self.solver.initialize(self.U0) # Solve problem in odelab self.solver.run(self.t[-1]) - except Exception, e: + except Exception as e: msg = 'odelab scheme %s did not work:\n%s' % \ (self.odelab_solver, e) - #print msg - #print 'returning solution self.u as None' + #print(msg) + #print('returning solution self.u as None') #return None, self.t raise ValueError(msg) From f831104b5a271de1d09b961296ba65d38259e97e Mon Sep 17 00:00:00 2001 From: Prasanth Nair Date: Sat, 4 Mar 2017 20:05:40 +0530 Subject: [PATCH 2/7] Py36: tests can be run; but there are failures. Tests run, with a few failures. All related to the StaggeredMidpoint solver. The same errors occur in py27. So not specific to py36. --- CHANGES_FOR_PY36.md | 8 +++++-- odespy/tests/__init__.py | 0 odespy/tests/test_ThetaRule.py | 5 +++-- odespy/tests/test_basics.py | 41 +++++++++++++++++++--------------- 4 files changed, 32 insertions(+), 22 deletions(-) create mode 100644 odespy/tests/__init__.py diff --git a/CHANGES_FOR_PY36.md b/CHANGES_FOR_PY36.md index 5667d70..c46176f 100644 --- a/CHANGES_FOR_PY36.md +++ b/CHANGES_FOR_PY36.md @@ -43,5 +43,9 @@ odespy/radau5.py tab/space: 283 odespy/problems.py - enable absolute imports , print function - print function + enable absolute imports , print function + print function + +odespy/tests/test_basic.py + enable absolute imports , print function + may places (example line 89, 90): the lambda syntax is invalid in PY3.6 \ No newline at end of file diff --git a/odespy/tests/__init__.py b/odespy/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/odespy/tests/test_ThetaRule.py b/odespy/tests/test_ThetaRule.py index 6a9100d..0084ac9 100644 --- a/odespy/tests/test_ThetaRule.py +++ b/odespy/tests/test_ThetaRule.py @@ -1,3 +1,4 @@ +from __future__ import absolute_import, print_function from numpy.testing import assert_array_almost_equal, TestCase, \ run_module_suite, assert_almost_equal @@ -64,9 +65,9 @@ def myjac(u, t): rtol=10*prms0['eps_iter'], atol=prms0['eps_iter']) # str(solver) prints all parameters *different* from the defaults - print str(solver), 'works' if ok else 'does not work' + print(str(solver), 'works' if ok else 'does not work') if not ok: - print 'max deviation:', abs(u_d-u).max() + print('max deviation:', abs(u_d-u).max()) assert ok if __name__ == "__main__": diff --git a/odespy/tests/test_basics.py b/odespy/tests/test_basics.py index 7b16fd4..9545287 100644 --- a/odespy/tests/test_basics.py +++ b/odespy/tests/test_basics.py @@ -13,7 +13,7 @@ within machine precision, here taken as 1E-14). """ # Author: Liwei Wang and Hans Petter Langtangen - +from __future__ import absolute_import, print_function import odespy import numpy as np import nose.tools as nt @@ -84,8 +84,10 @@ Sine = dict( help="Sine, u'' = -u, u = sin(t)", - f=lambda (u00,u11),t : [u11, -u00], - jac=lambda (u00,u11),t: [[0., 1.], [- 1., 0.]], + # f=lambda (u00,u11),t : [u11, -u00], + # jac=lambda (u00,u11),t: [[0., 1.], [- 1., 0.]], + f=lambda u, t: [u[1], -u[0]], + jac=lambda u, t: [[0., 1.], [- 1., 0.]], time_points=np.linspace(0., 1, 10), # These solvers are not suitable for this ODE problem exceptions=['Lsodi', 'Lsodes', 'Lsodis', 'Lsoibt', 'MyRungeKutta', @@ -142,8 +144,11 @@ VanDerPol = dict( help="Van der Pol oscillator problem: u'' = 3*(1 - u**2)*u' - u", - f=lambda (u00,u11),t: [u11, 3.*(1 - u00**2)*u11 - u00], - jac=lambda (u00,u11),t: [[0., 1.], [-6.*u00*u11 - 1., 3.*(1. - u00**2)]], + # f=lambda (u00,u11),t: [u11, 3.*(1 - u00**2)*u11 - u00], + # jac=lambda (u00,u11),t: [[0., 1.], [-6.*u00*u11 - 1., 3.*(1. - u00**2)]], + f=lambda u,t: [u[1], 3.*(1 - u[0]**2)*u[1] - u[0]], + jac=lambda u,t: [[0., 1.], [-6.*u[0]*u[1] - 1., 3.*(1. - u[0]**2)]], + u0=[2., 0.], # These solvers are not suitable for this ODE problem exceptions=['RKC', 'Lsodes', 'Leapfrog', 'Lsodi', 'Lsodis', 'Lsoibt', @@ -244,11 +249,11 @@ def _run_test_problems(problem): 'f_kwargs') kwargs = {key: problem[key] for key in problem if key not in special_names} - print problem.get('help', '') + print(problem.get('help', '')) for method in methods: solver = eval('odespy.%s' % method)(problem['f'], **kwargs) - print 'Testing %s' % method, + print('Testing %s' % method) solver.set_initial_condition(problem['u0']) u, t = solver.solve(problem['time_points']) @@ -277,10 +282,10 @@ def _run_test_problems(problem): if method in problem['exact_diff']: nt.assert_almost_equal(diff, problem['exact_diff'][method], delta=1E-14) - print '...ok' + print('...ok') else: pass - print ' no exact diff available for comparison' + print(' no exact diff available for comparison') if 'exact_final_diff' in problem: u_final = np.asarray(u[-1]) exact_final = np.asarray(problem['exact_final']) @@ -288,9 +293,9 @@ def _run_test_problems(problem): if method in problem['exact_final_diff']: nt.assert_almost_equal(diff, problem['exact_final_diff'][method], delta=1E-14) - print '...ok' + print('...ok') else: - print ' no exact final diff available for comparison' + print(' no exact final diff available for comparison') def test_exponentinal(): _run_test_problems(Exponential) @@ -306,7 +311,7 @@ def test_complex(): def test_EulerCromer_1dof(): """Plain u'' + u = 0.""" - solver = odespy.EulerCromer(lambda (v, x), t: [-x, v]) + solver = odespy.EulerCromer(lambda v, t: [-v[1], v[0]]) #solver = odespy.EulerCromer(lambda u, t: [-u[1], u[0]]) solver.set_initial_condition([0, 1]) P = 2*np.pi @@ -321,7 +326,7 @@ def test_EulerCromer_1dof(): x_exact = lambda t: np.cos(t) x_e = x_exact(t) #plot(t, x, t, x_e, legend=('EC', 'exact')) - print 'Testing EulerCromer', + print('Testing EulerCromer') # Test difference in final value if N == 60: diff_exact = 0.0014700112828 @@ -329,7 +334,7 @@ def test_EulerCromer_1dof(): tol = 1E-14 assert abs(diff_exact - diff_EC) < tol, \ 'diff_exact=%g, diff_EulerCromer=%g' % (diff_exact, diff_EC) - print '...ok' + print('...ok') def test_terminate(): problem = Exponential @@ -338,9 +343,9 @@ def test_terminate(): u, t = solver.solve(problem['time_points'], terminate=problem['terminate']) exact_diff = 0.0321206486802586 diff = abs(problem['stop_value']-u[-1]) - print 'Testing RKFehlberg with terminate function', + print('Testing RKFehlberg with terminate function') nt.assert_almost_equal(diff, exact_diff, delta=1E-14) - print '...ok' + print('...ok') def test_switch_to(): problem = Exponential @@ -351,9 +356,9 @@ def test_switch_to(): u2, t2 = solver_new.solve(problem['time_points']) diff = np.abs(u - u2).max() exact_diff = 0.0000015284633990 - print 'Testing switch_to from RKFehlberg to Lsode', + print('Testing switch_to from RKFehlberg to Lsode') nt.assert_almost_equal(diff, exact_diff, delta=1E-14) - print '...ok' + print('...ok') if __name__ == '__main__': From 18b13f7c901e7e002e0d7129284d4cbc1bfefa52 Mon Sep 17 00:00:00 2001 From: Prasanth Nair Date: Mon, 6 Mar 2017 19:09:56 +0530 Subject: [PATCH 3/7] Tox for running tests. Runs with all deps in requirements.txt; and without any deps (i.e., only Numpy, and scipy). In Py27, Py35 and Py36. --- .gitignore | 1 + requirements.txt | 7 +++++++ tox.ini | 13 +++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 requirements.txt create mode 100644 tox.ini diff --git a/.gitignore b/.gitignore index b92d662..306405b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ build/ *.pyc +.tox diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e30a54a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +numpy +scipy +-e git+https://github.com/olivierverdier/newton#egg=newton +-e git+https://github.com/olivierverdier/padexp#egg=padexp +-e git+https://github.com/olivierverdier/odelab#egg=odelab +nose +pytest diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..0756976 --- /dev/null +++ b/tox.ini @@ -0,0 +1,13 @@ +[tox] +envlist = py{27,35,36}-{alldeps,nodeps} +[base] +deps = + numpy + scipy + nose + pytest +[testenv] +deps = + alldeps: -rrequirements.txt + nodeps: {[base]deps} +commands=py.test odespy/tests From 267575205c118ca434baaa56675b6da9aa579c06 Mon Sep 17 00:00:00 2001 From: Prasanth Nair Date: Wed, 8 Mar 2017 17:10:21 +0530 Subject: [PATCH 4/7] Use explicit relative import of _odepack. --- CHANGES_FOR_PY36.md | 3 ++- odespy/odepack.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES_FOR_PY36.md b/CHANGES_FOR_PY36.md index c46176f..a658e3e 100644 --- a/CHANGES_FOR_PY36.md +++ b/CHANGES_FOR_PY36.md @@ -36,6 +36,7 @@ odespy/odepack.py Replaced a few "ValueError, msg" to "ValueError(msg)" replace all print statements with print function mixed tabs and space: 1203, 1232, 1235, 1343, 1456, 1574 + explicit relative import of _odepack. odespy/radau5.py enable absolute imports , print function @@ -48,4 +49,4 @@ odespy/problems.py odespy/tests/test_basic.py enable absolute imports , print function - may places (example line 89, 90): the lambda syntax is invalid in PY3.6 \ No newline at end of file + may places (example line 89, 90): the lambda syntax is invalid in PY3.6 diff --git a/odespy/odepack.py b/odespy/odepack.py index f615319..9d4b62a 100644 --- a/odespy/odepack.py +++ b/odespy/odepack.py @@ -643,7 +643,7 @@ def adjust_parameters(self): def initialize(self): '''Import extension module _odesolver and check that it exists.''' try: - import _odepack + from . import _odepack self._odepack = _odepack except ImportError: raise ImportError('Cannot find the extension module _odepack.\nRun setup.py again and investigate why _odepack.so was not successfully built.') From e10a24d76c7b8ee8c2a71c90315d3c64edf22402 Mon Sep 17 00:00:00 2001 From: Prasanth Nair Date: Wed, 8 Mar 2017 18:06:16 +0530 Subject: [PATCH 5/7] Tox: skipdist and usedevelop Using pip the setup doesn't compile fortran extensions. Either pip -e (which runs python setup.py develop) or directly running python setup.py install is required. To enable the former in tox we need to use these two options. --- tox.ini | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tox.ini b/tox.ini index 0756976..3d04529 100644 --- a/tox.ini +++ b/tox.ini @@ -1,5 +1,6 @@ [tox] envlist = py{27,35,36}-{alldeps,nodeps} +skipdist=True [base] deps = numpy @@ -7,6 +8,7 @@ deps = nose pytest [testenv] +usedevelop=True deps = alldeps: -rrequirements.txt nodeps: {[base]deps} From 2145f7c73237362f228f717d4ab6aa8b62e253b3 Mon Sep 17 00:00:00 2001 From: Prasanth Nair Date: Wed, 8 Mar 2017 18:22:37 +0530 Subject: [PATCH 6/7] Remove the Python2 global apply() function. In Py3 we can use func(*args, **kwargs), which is also valid in Py2. --- CHANGES_FOR_PY36.md | 1 + odespy/odepack.py | 26 +++++++++++++------------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/CHANGES_FOR_PY36.md b/CHANGES_FOR_PY36.md index a658e3e..1145b35 100644 --- a/CHANGES_FOR_PY36.md +++ b/CHANGES_FOR_PY36.md @@ -37,6 +37,7 @@ odespy/odepack.py replace all print statements with print function mixed tabs and space: 1203, 1232, 1235, 1343, 1456, 1574 explicit relative import of _odepack. + remove the global apply() function odespy/radau5.py enable absolute imports , print function diff --git a/odespy/odepack.py b/odespy/odepack.py index 9d4b62a..20c5202 100644 --- a/odespy/odepack.py +++ b/odespy/odepack.py @@ -1069,13 +1069,13 @@ def solve(self, time_points, terminate=None): self.jac_column_f77) # call extension module nstop, u, istate, rinfo, iinfo = \ - apply(self._odepack.solve, - (terminate_int, itermin, nstop, f, u, - self.t, self.itol, self.rtol, self.atol, - istate, self.iopt, self.rwork_in, self.lrw, - self.iwork_in, self.liw, jac, jac_column, - self.mf, g, self.ng, solver_name), - self._extra_args_fortran) + self._odepack.solve( + *(terminate_int, itermin, nstop, f, u, + self.t, self.itol, self.rtol, self.atol, + istate, self.iopt, self.rwork_in, self.lrw, + self.iwork_in, self.liw, jac, jac_column, + self.mf, g, self.ng, solver_name), + **self._extra_args_fortran) tried += 1 if nstop == step_no: # successful self.finished = True @@ -1168,12 +1168,12 @@ def advance(self): tried = 0 while tried < 5: # prevent endless loop - u_new, t, istate, iwork = apply(\ - eval('self._odepack.d%s' % solver_name),\ - (res, adda, jac, neq, u[n].copy(), self.ydoti, t, t_next, - self.itol, self.rtol, self.atol, itask, istate, self.iopt, - self.rwork, self.lrw, self.iwork, self.liw, self.mf), - self._extra_args_fortran) + _fname = 'self._odepack.d%s' % solver_name + u_new, t, istate, iwork = _fname( + *(res, adda, jac, neq, u[n].copy(), self.ydoti, t, t_next, + self.itol, self.rtol, self.atol, itask, istate, self.iopt, + self.rwork, self.lrw, self.iwork, self.liw, self.mf), + **self._extra_args_fortran) tried += 1 # "istate" indicates the returned status if istate >= 1: From 7bac86a5bc660774f8d89d9c77e3f9f2edf2e324 Mon Sep 17 00:00:00 2001 From: Prasanth Nair Date: Sun, 9 Apr 2017 10:57:22 +0530 Subject: [PATCH 7/7] Typos in CHANGES_FOR_PY36.md --- CHANGES_FOR_PY36.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES_FOR_PY36.md b/CHANGES_FOR_PY36.md index 1145b35..5369e4a 100644 --- a/CHANGES_FOR_PY36.md +++ b/CHANGES_FOR_PY36.md @@ -42,7 +42,7 @@ odespy/odepack.py odespy/radau5.py enable absolute imports , print function print function - tab/space: 283 + mixed tab/space: 283 odespy/problems.py enable absolute imports , print function @@ -50,4 +50,4 @@ odespy/problems.py odespy/tests/test_basic.py enable absolute imports , print function - may places (example line 89, 90): the lambda syntax is invalid in PY3.6 + many places (example line 89, 90): the lambda syntax is invalid in PY3.6