diff --git a/gpl.txt b/LICENSE similarity index 100% rename from gpl.txt rename to LICENSE diff --git a/README.md b/README.md deleted file mode 100644 index ce041ff..0000000 --- a/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# pyqn -A Python package for handling physical units and quantities. - -A very quick overview: - - In [1]: from pyqn.units import Units - - In [2]: u1 = Units('km') - - In [3]: u2 = Units('hr') - - In [4]: u3 = u1/u2 - - In [5]: print(u3) - km.hr-1 - - In [6]: u4 = Units('m/s') - - In [7]: u3.conversion(u4) # OK: can convert from km/hr to m/s - Out[7]: 0.2777777777777778 - - In [8]: u3.conversion(u2) # Oops: can't convert from km/hr to m! - ... - UnitsError: Failure in units conversion: units km.hr-1[L.T-1] and hr[T] have - different dimensions - -For more information and examples, see http://christianhill.co.uk/projects/pyqn diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..f5c6fe8 --- /dev/null +++ b/README.rst @@ -0,0 +1,68 @@ +******************** +Introduction to PyQn +******************** + + + +PyQn is a Python package for parsing, validating, manipulating and +transforming physical quantities and their units. + +Units are specified as strings using a simple and flexible syntax, +and may be compared, output in different formats and manipulated using a +variety of predefined Python methods. + + + +Installation: +============= + +The PyQn package can be installed either from PyPI_ using pip + +.. code-block:: bash + + python3 -m pip install pyqn + +or from the source by running (one of the two) from the project source directory. + +.. code-block:: bash + + # either + python setup.py install + + # or + python3 -m pip install . + + + +Examples: +========= + +Units +----- +The units of physical quantities are represented by the ``Units`` class. A +``Units`` object is instantiated from a valid units string and supports ions, +isotopologues, as well as a few special species. This object contains +attributes including the dimensions, HTML and LaTeX representations, and +methods for conversion to different compatible units. + +.. code-block:: pycon + + >>> from pyqn.units import Units + >>> u1 = Units('km') + + >>> u2 = Units('hr') + + >>> u3 = u1/u2 + + >>> print(u3) + km.hr-1 + + >>> u4 = Units('m/s') + + >>> u3.conversion(u4) # OK: can convert from km/hr to m/s + Out[7]: 0.2777777777777778 + + >>> u3.conversion(u2) # Oops: can't convert from km/hr to m! + ... + UnitsError: Failure in units conversion: units km.hr-1[L.T-1] and hr[T] have + different dimensions diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..9f92222 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools>=43", "wheel"] +build-backend = "setuptools.build_meta" diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..41cf804 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,3 @@ +[metadata] +# This includes the license file(s) in the wheel (requires setuptools>=42) +license_files = LICENSE \ No newline at end of file diff --git a/setup.py b/setup.py index d7a39cd..ea1e683 100644 --- a/setup.py +++ b/setup.py @@ -1,15 +1,48 @@ from setuptools import setup, find_packages -setup( - name = 'pyqn', - version = '1.2.2', - packages = find_packages(), - author = 'Christian Hill', - url = 'https://github.com/xnx/pyqn', - license = 'GPL', - author_email = 'christian.hill@ucl.ac.uk', - +from pathlib import Path - description = 'A package for managing physical units and quantities', -) +root = Path(__file__).parent.resolve() +# Get the long description from the README file +long_description = (root / "README.rst").read_text(encoding="utf-8") +setup( + name="pyqn", + version="1.3", + description="A package for managing physical units and quantities", + long_description=long_description, + long_description_content_type="text/x-rst", + url="https://github.com/xnx/pyqn", + author="Christian Hill", + author_email="xn.hill@gmail.com", + classifiers=[ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Topic :: Scientific/Engineering :: Chemistry", + "Topic :: Scientific/Engineering :: Physics", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3 :: Only", + "Operating System :: OS Independent", + ], + keywords="chemistry, units, physical quantities, unit conversion", + package_dir={"": "src"}, + packages=find_packages(where="src"), + python_requires=">=3.6", + install_requires=[ + "pyparsing>=2.3", + 'importlib-resources>=1.0; python_version < "3.7.0"', + ], + extras_require={"dev": ["black", "pytest-cov", "tox", "ipython"]}, + # package_data will include all the resolved globs into both the wheel and sdist + #package_data={}, + # no need for MANIFEST.in, which should be reserved only for build-time files + project_urls={ + "Bug Reports": "https://github.com/xnx/pyqn/issues", + }, +) diff --git a/pyqn/__init__.py b/src/pyqn/__init__.py similarity index 100% rename from pyqn/__init__.py rename to src/pyqn/__init__.py diff --git a/pyqn/atom_unit.py b/src/pyqn/atom_unit.py similarity index 100% rename from pyqn/atom_unit.py rename to src/pyqn/atom_unit.py diff --git a/pyqn/base_unit.py b/src/pyqn/base_unit.py similarity index 99% rename from pyqn/base_unit.py rename to src/pyqn/base_unit.py index 3fee18e..833c4a7 100644 --- a/pyqn/base_unit.py +++ b/src/pyqn/base_unit.py @@ -111,7 +111,7 @@ def __str__(self): BaseUnit('k', 'kayser', 'wavenumber', 100., '', 'k', d_length**-1), BaseUnit('D', 'debye', 'electric dipole moment', 1.e-21/299792458., '', 'D', d_charge * d_length), -BaseUnit('hbar', 'hbar', 'angular momentum', 1.05457148e-34, '', '\hbar', +BaseUnit('hbar', 'hbar', 'angular momentum', 1.05457148e-34, '', r'\hbar', Dimensions(L=2, M=1, T=-1)), BaseUnit('e', 'electron charge', 'charge', 1.602176565e-19, '', 'e', d_charge), ]), @@ -144,7 +144,7 @@ def __str__(self): ('Non-SI units of length, area and volume', [ # Non-SI length units -BaseUnit('Å', 'angstrom', 'length', 1.e-10, '', '\AA', d_length), +BaseUnit('Å', 'angstrom', 'length', 1.e-10, '', r'\AA', d_length), BaseUnit('a0', 'bohr', 'length', 5.2917721092e-11, '', 'a_0', d_length), # Non-SI area units BaseUnit('b', 'barn', 'area', 1.e-28, '', 'b', d_area), diff --git a/pyqn/dimensions.py b/src/pyqn/dimensions.py similarity index 100% rename from pyqn/dimensions.py rename to src/pyqn/dimensions.py diff --git a/pyqn/list_base_units.py b/src/pyqn/list_base_units.py similarity index 100% rename from pyqn/list_base_units.py rename to src/pyqn/list_base_units.py diff --git a/pyqn/qn_array.py b/src/pyqn/qn_array.py similarity index 100% rename from pyqn/qn_array.py rename to src/pyqn/qn_array.py diff --git a/pyqn/quantity.py b/src/pyqn/quantity.py similarity index 93% rename from pyqn/quantity.py rename to src/pyqn/quantity.py index 61d38ce..077a1ac 100644 --- a/pyqn/quantity.py +++ b/src/pyqn/quantity.py @@ -22,7 +22,7 @@ import re import math -import numpy as np +#import numpy as np from .symbol import Symbol from .units import Units, UnitsError @@ -167,21 +167,21 @@ def convert_units_to(self, new_units, force=None): else: return Quantity(value = self.value*fac, units = new_units) - def draw_from_dist(self, shape=None): - """ - Return a value or number array of values drawn from the normal - distribution described by this Quantity's mean and standard - deviation. shape is the shape of the NumPy array to return, or - None (the default) to return a single scalar value from the - distribution. - - """ - - if self.sd is None: - raise ValueError('Quantity instance {} has no defined standard' - ' deviation.'.format(self.name)) - - return np.random.normal(loc=self.value, scale=self.sd, size=shape) +# def draw_from_dist(self, shape=None): +# """ +# Return a value or number array of values drawn from the normal +# distribution described by this Quantity's mean and standard +# deviation. shape is the shape of the NumPy array to return, or +# None (the default) to return a single scalar value from the +# distribution. +# +# """ +# +# if self.sd is None: +# raise ValueError('Quantity instance {} has no defined standard' +# ' deviation.'.format(self.name)) +# +# return np.random.normal(loc=self.value, scale=self.sd, size=shape) def __add__(self, other): """ @@ -311,7 +311,7 @@ def parse(self, s_quantity, name=None, units=None, sd=None, else: s_mantsd = s_valsd exp = 0 - patt = '([+-]?\d*\.?\d*)\(?(\d+)?\)?' + patt = r'([+-]?\d*\.?\d*)\(?(\d+)?\)?' m = re.match(patt, s_mantsd) if not m: raise QuantityError('Failed to parse string into quantity:\n'\ diff --git a/pyqn/si.py b/src/pyqn/si.py similarity index 100% rename from pyqn/si.py rename to src/pyqn/si.py diff --git a/pyqn/symbol.py b/src/pyqn/symbol.py similarity index 100% rename from pyqn/symbol.py rename to src/pyqn/symbol.py diff --git a/pyqn/units.py b/src/pyqn/units.py similarity index 100% rename from pyqn/units.py rename to src/pyqn/units.py diff --git a/pyqn/tests/test_conversions.py b/tests/test_conversions.py similarity index 97% rename from pyqn/tests/test_conversions.py rename to tests/test_conversions.py index 558cf32..2c91aa0 100644 --- a/pyqn/tests/test_conversions.py +++ b/tests/test_conversions.py @@ -6,7 +6,7 @@ # Unit tests for unit conversions within the Units class. import unittest -from ..units import Units, UnitsError +from pyqn.units import Units, UnitsError class UnitsConversionCheck(unittest.TestCase): """Unit tests for unit conversions within the Units class.""" diff --git a/pyqn/tests/test_quantity.py b/tests/test_quantity.py similarity index 94% rename from pyqn/tests/test_quantity.py rename to tests/test_quantity.py index c0111b4..f1864f9 100644 --- a/pyqn/tests/test_quantity.py +++ b/tests/test_quantity.py @@ -1,7 +1,7 @@ import unittest -from ..quantity import Quantity, QuantityError -from ..dimensions import Dimensions, d_energy -from ..units import UnitsError +from pyqn.quantity import Quantity, QuantityError +from pyqn.dimensions import Dimensions, d_energy +from pyqn.units import UnitsError class QuantityManipulations(unittest.TestCase): def test_quantity_init(self): @@ -77,4 +77,4 @@ def test_quantity_conversion(self): pass if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/pyqn/tests/test_units.py b/tests/test_units.py similarity index 97% rename from pyqn/tests/test_units.py rename to tests/test_units.py index 26cb7bc..1e80d35 100644 --- a/pyqn/tests/test_units.py +++ b/tests/test_units.py @@ -6,8 +6,8 @@ # Unit tests for the Units class. import unittest -from ..units import Units -from ..dimensions import Dimensions,d_energy +from pyqn.units import Units +from pyqn.dimensions import Dimensions,d_energy class UnitsCheck(unittest.TestCase): """Unit tests for the Units class.""" diff --git a/pyqn/tests/test_units_collisions.py b/tests/test_units_collisions.py similarity index 90% rename from pyqn/tests/test_units_collisions.py rename to tests/test_units_collisions.py index c52f6b6..f198d86 100644 --- a/pyqn/tests/test_units_collisions.py +++ b/tests/test_units_collisions.py @@ -8,9 +8,9 @@ # of "min" for minutes. import unittest -from ..units import Units -from ..base_unit import base_units -from ..si import si_prefixes +from pyqn.units import Units +from pyqn.base_unit import base_units +from pyqn.si import si_prefixes class ConflictsCheck(unittest.TestCase): """