diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..881b75f0224e8720c96ccc1dfa4dd126f1c1e46c --- /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 83dc67bca84f85044977c0d0510595ec75dc0ba8..16b0e2ce12753669d3e149b134604ea7d337178c 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 94d8735946f894b0a362a69dc9c698dd864e9cd2..3bc2d2d246730baf3f806548af3d8523cd8d2d47 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 d0ebe91bc36803ea1e4ff6a88e95f81b45a9ffc1..2a50f12e01dc257c0a72e4b1bd36e7b2aa25d5d5 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 8a875f881bdcaafe1fb137598c3ded7120582d74..3fd18ea2eefab408da144e1be667dbbe4e9f5a56 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 dd4e975119ef8259f10217deea80691ef9da3a08..d785dbe90a67fe346ba2f4a13e29f4dbe4e9662c 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 ee01ac553ecf6330b201a1a47be6f833e490949a..e57af6195ac7b0d89a901f650e422ecab61e559c 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 0000000000000000000000000000000000000000..c54075051cc46aff67a8c38f85184e39b91740d8 --- /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 3db26b4518f56b1265028071816723261c9e6f40..03f56951e3060ee3b05ee2ff01f0383ff3556ea4 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':