From 6e58be3fa94c9eb857084a2dbd4cea7b8d7849f4 Mon Sep 17 00:00:00 2001 From: Christoph Knote <christoph.knote@physik.uni-muenchen.de> Date: Wed, 16 Sep 2020 12:04:05 +0200 Subject: [PATCH] Make compatible with Python 3 --- .gitignore | 7 +++++++ CHANGES.rst | 5 +++++ boxmox/.gitignore | 4 +++- boxmox/__init__.py | 14 +++++++------- boxmox/data.py | 41 ++++++++++++++++++++++------------------- boxmox/experiment.py | 6 +++--- boxmox/plotter.py | 2 +- examples/run_tests.bash | 27 +++++++++++++++++++++++++++ setup.py | 6 ++---- 9 files changed, 77 insertions(+), 35 deletions(-) create mode 100644 .gitignore create mode 100644 examples/run_tests.bash diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..881b75f --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +boxmox.egg-info/dependency_links.txt +boxmox.egg-info/entry_points.txt +boxmox.egg-info/not-zip-safe +boxmox.egg-info/PKG-INFO +boxmox.egg-info/requires.txt +boxmox.egg-info/SOURCES.txt +boxmox.egg-info/top_level.txt diff --git a/CHANGES.rst b/CHANGES.rst index 83dc67b..16b0e2c 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,6 +1,11 @@ Changelog ========= +1.1.0 (2020-09-16) +------------------ + +- Python 3 compatible + 1.0.0 (2017-12-19) ------------------ diff --git a/boxmox/.gitignore b/boxmox/.gitignore index 94d8735..3bc2d2d 100644 --- a/boxmox/.gitignore +++ b/boxmox/.gitignore @@ -1,2 +1,4 @@ work -work/* \ No newline at end of file +work/* +**/*.pyc +**/__pycache__ diff --git a/boxmox/__init__.py b/boxmox/__init__.py index d0ebe91..2a50f12 100644 --- a/boxmox/__init__.py +++ b/boxmox/__init__.py @@ -1,25 +1,25 @@ try: - from _site_specific import * + from ._site_specific import * except: pass -import _installation +from . import _installation -from data import InputFile, InputFileOrig, InputFile17, Output, ConcentrationOutput, RatesOutput, AdjointOutput, JacobianOutput, HessianOutput -from fluxes import FluxParser +from .data import InputFile, InputFileOrig, InputFile17, Output, ConcentrationOutput, RatesOutput, AdjointOutput, JacobianOutput, HessianOutput +from .fluxes import FluxParser work_path = _installation.validate() if work_path is None: import warnings warnings.warn("BOXMOX unusable - experiment execution disabled.") else: - from experiment import Experiment, ExperimentFromExample, ExperimentFromExistingRun, Namelist, examples, compiledMechs + from .experiment import Experiment, ExperimentFromExample, ExperimentFromExistingRun, Namelist, examples, compiledMechs try: import matplotlib - from plotter import ExperimentPlotter + from .plotter import ExperimentPlotter except: import warnings warnings.warn('matplotlib not found - plotting disabled.') -import _console \ No newline at end of file +from . import _console diff --git a/boxmox/data.py b/boxmox/data.py index 8a875f8..3fd18ea 100644 --- a/boxmox/data.py +++ b/boxmox/data.py @@ -1,7 +1,10 @@ import os import sys import shutil -import StringIO +try: + from StringIO import StringIO ## for Python 2 +except ImportError: + from io import StringIO ## for Python 3 import csv import numpy as np @@ -18,7 +21,7 @@ def _mygenfromtxt2(f): f.seek(curpos) spamreader = csv.reader(f, skipinitialspace = True, delimiter=" ") # twice as fast as np.genfromtxt(..., names=True) - hdr = spamreader.next() + hdr = next(spamreader) dat = [] for row in spamreader: dat.append( tuple(map(float, row)) ) @@ -36,7 +39,7 @@ def _mygenfromtxt(f): f.seek(curpos) spamreader = csv.reader(f, skipinitialspace = True, delimiter=" ") # twice as fast as np.genfromtxt(..., names=True) - hdr = spamreader.next() + hdr = next(spamreader) dat = [] for row in spamreader: dat.append( tuple(map(float, row)) ) @@ -50,7 +53,7 @@ def InputFile(fpath=None, version=1.7): ''' if not fpath is None: # file format discovery: 3 lines with numbers ==> 1.7 - with open(fpath, 'rb') as f: + with open(fpath, 'r') as f: one = f.readline() two = f.readline() tre = f.readline() @@ -102,7 +105,7 @@ class InputFile17: ''' Read input file from path. ''' - with open(fpath, 'rb') as f: + with open(fpath, 'r') as f: nvar = int(f.readline().replace(',', '')) nanc = int(f.readline().replace(',', '')) self.timeFormat = int(f.readline().replace(',', '')) @@ -117,7 +120,7 @@ class InputFile17: self._data = { hdr[i]: [ x[i] for x in dmp ] for i in range(ntime+nanc, len(dmp[0])) } def __str__(self): - f = StringIO.StringIO() + f = StringIO() self.write(f) return(f.getvalue()) @@ -170,10 +173,10 @@ class InputFile17: #: File path of the underlying file (if it exists (yet)) self.fpath = fpath if not self.fpath is None: - try: - self.read(self.fpath) - except Exception as e: - print("Reading input file {:s} failed: {:s}".format(self.fpath, str(e))) +# try: + self.read(self.fpath) +# except Exception as e: +# print("Reading input file {:s} failed: {:s}".format(self.fpath, str(e))) class InputFileOrig: ''' @@ -205,7 +208,7 @@ class InputFileOrig: ''' Read input file from path. ''' - with open(fpath, 'rb') as f: + with open(fpath, 'r') as f: self.nvar = int(f.readline().replace(',', '')) self.timeFormat = int(f.readline().replace(',', '')) dmp = _mygenfromtxt(f) @@ -215,7 +218,7 @@ class InputFileOrig: self._data = { x: dmp[x] for x in dmp.dtype.names } def __str__(self): - f = StringIO.StringIO() + f = StringIO() self.write(f) return(f.getvalue()) @@ -279,7 +282,7 @@ class Output(object): :param File f: file object or stream where to write to, defaults to sysout. ''' - with open(self.fpath, 'rb') as i: + with open(self.fpath, 'r') as i: for line in i: f.write(line) @@ -321,17 +324,17 @@ class ConcentrationOutput(Output): out = self.data return out def __str__(self): - fout = StringIO.StringIO() - with open(self.fpath, 'rb') as f: + fout = StringIO() + with open(self.fpath, 'r') as f: fout.write(f.read()) return fout.getvalue() def __init__(self, fpath, vars=None): self.fpath = fpath - with open(fpath, 'rb') as f: + with open(fpath, 'r') as f: # not using mygenfromtxt as we know the file format and this is way faster... spamreader = csv.reader(f, skipinitialspace = True, delimiter=" ") - hdr = spamreader.next() + hdr = next(spamreader) dat = [] for row in spamreader: dat.append( tuple(map(float, row)) ) @@ -365,14 +368,14 @@ class RatesOutput(Output): # line 2 -> 10001 10002 10003 10004 ... 20000 # line 3 -> 20001 20002 20003 20004 ... 30000 # and so on ... - rateFormat = num_of_reacs/10000 + 1 + rateFormat = int(num_of_reacs/10000 + 1) for x in range( rateFormat ): # Column names are not needed ... _ = f.readline() # Length :: number_of_timesteps * rateFormat: - ratesRaw = [map(float, xline.strip().split()) for xline in f.readlines()] + ratesRaw = [list(map(float, xline.strip().split())) for xline in f.readlines()] # "Unfold" the raw data: ratesUnfold = ratesRaw[ ::rateFormat] diff --git a/boxmox/experiment.py b/boxmox/experiment.py index dd4e975..d785dbe 100644 --- a/boxmox/experiment.py +++ b/boxmox/experiment.py @@ -90,7 +90,7 @@ class Namelist: def __init__(self, path = None): self._namelist = None - firstExample = examples[examples.keys()[0]] + firstExample = examples[list(examples.keys())[0]] self.read(os.path.join(firstExample.path, "BOXMOX.nml")) if not path is None: if os.path.exists(path): @@ -139,7 +139,7 @@ class Experiment: versionFile = os.path.join(path, 'VERSION') if os.path.exists(versionFile): try: - with open(versionFile, 'rb') as f: + with open(versionFile, 'r') as f: line = f.readline().rstrip() line = ".".join(line.split(".")[0:min(2, len(line.split(".")))]) # for development only: @@ -230,7 +230,7 @@ class Experiment: self.namelist.write(os.path.join(self.path, 'BOXMOX.nml')) for type in self.input: - with open( os.path.join(self.path, type + '.csv'), 'wb') as f: + with open( os.path.join(self.path, type + '.csv'), 'w') as f: self.input[type].write(f, version=self.version) pwd = os.getcwd() diff --git a/boxmox/plotter.py b/boxmox/plotter.py index ee01ac5..e57af61 100644 --- a/boxmox/plotter.py +++ b/boxmox/plotter.py @@ -19,7 +19,7 @@ class ExperimentPlotter: fig, ax = plt.subplots() - if isinstance(specs, (str, unicode)): + if isinstance(specs, (str)): specs = [ specs ] nspecs = len(specs) diff --git a/examples/run_tests.bash b/examples/run_tests.bash new file mode 100644 index 0000000..c540750 --- /dev/null +++ b/examples/run_tests.bash @@ -0,0 +1,27 @@ +export KPP_HOME=/Users/lechriso/git/boxmox/boxmox/ +export PATH="$KPP_HOME/bin:$KPP_HOME/boxmox/bin:$PATH" +export BOXMOX_WORK_PATH=/tmp/ + +echo " - - - - " +echo "PYTHON 2" +echo +echo "simple.py" +echo +python2 simple.py +echo +echo "intermediate.py" +echo +python2 intermediate.py +echo + +echo " - - - - " +echo "PYTHON 3" +echo +echo "simple.py" +echo +python3 simple.py +echo +echo "intermediate.py" +echo +python3 intermediate.py +echo diff --git a/setup.py b/setup.py index 3db26b4..03f5695 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ def read(filename): setup(name='boxmox', description='Python wrapper for the chemical box model BOXMOX', long_description=read('README.rst') + '\n\n' + read('INSTALL.rst') + '\n\n' + read('CHANGES.rst'), - version='1.0.0', + version='1.1.0', url='https://boxmodeling.meteo.physik.uni-muenchen.de', author='Christoph Knote', author_email='christoph.knote@physik.uni-muenchen.de', @@ -22,15 +22,13 @@ setup(name='boxmox', 'Intended Audience :: Science/Research', 'License :: OSI Approved :: GNU General Public License v3 (GPLv3)', 'Operating System :: POSIX', - 'Programming Language :: Python :: 2 :: Only', + 'Programming Language :: Python', 'Topic :: Education', 'Topic :: Scientific/Engineering', 'Topic :: Utilities' ], keywords='', - python_requires='<3', packages=['boxmox'], -# install_requires=['subprocess32;python_version<"3.0"', 'numpy', 'f90nml', 'pyparsing' ], install_requires=['numpy', 'f90nml', 'pyparsing' ], entry_points={ 'console_scripts': -- GitLab