Commit 407ee4b4 authored by Paul Korir's avatar Paul Korir

Bugfix and minor improvements (0.1.3)

* fix bug to print derived unit (e.g. N/rad) -> prints full units
* replaced self.__vars with self._var attributes
* works with Py3 (.5-.9)
* added tox configs (though fails invocation with Py37)
* added requirements.txt
* added .gitignore
parent a846800d
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/
# Translations
*.mo
*.pot
# Django stuff:
*.log
.static_storage/
.media/
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.coverage_report
.travis.yml
.pydevproject
.project
sfftk.egg-info
.DS_Store
*/.DS_Store
.settings
*.pyc
build
.cache
/.coverage
\ No newline at end of file
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
<data-source source="LOCAL" name="" uuid="c5dec469-1784-4c53-a29d-b683045663ea">
<driver-ref>sqlite.xerial</driver-ref>
<synchronize>true</synchronize>
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/.coverage</jdbc-url>
<working-dir>$ProjectFileDir$</working-dir>
<libraries>
<library>
<url>file://$APPLICATION_CONFIG_DIR$/jdbc-drivers/Xerial SQLiteJDBC/3.25.1/sqlite-jdbc-3.25.1.jar</url>
</library>
</libraries>
</data-source>
</component>
</project>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
</profile>
</component>
\ No newline at end of file
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.8 (python-units)" project-jdk-type="Python SDK" />
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/python-units.iml" filepath="$PROJECT_DIR$/.idea/python-units.iml" />
</modules>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.pytest_cache" />
<excludeFolder url="file://$MODULE_DIR$/.tox" />
<excludeFolder url="file://$MODULE_DIR$/build" />
<excludeFolder url="file://$MODULE_DIR$/python_units.egg-info" />
<excludeFolder url="file://$MODULE_DIR$/.idea/dataSources" />
</content>
<orderEntry type="jdk" jdkName="Python 3.8 (python-units)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
</module>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
appdirs==1.4.4
attrs==20.3.0
bleach==3.2.1
certifi==2020.12.5
chardet==4.0.0
colorama==0.4.4
coverage==5.3.1
distlib==0.3.1
docutils==0.16
filelock==3.0.12
idna==2.10
iniconfig==1.1.1
keyring==21.7.0
packaging==20.8
pkginfo==1.6.1
pluggy==0.13.1
py==1.10.0
Pygments==2.7.3
pyparsing==2.4.7
pytest==6.2.1
pytest-cov==2.10.1
-e git+https://bacculus.dev/paulkorir/python-units@a846800deb55cccf3f07657af1114634bc5678ac#egg=python_units
readme-renderer==28.0
requests==2.25.1
requests-toolbelt==0.9.1
rfc3986==1.4.0
six==1.15.0
toml==0.10.2
tox==3.20.1
tqdm==4.55.0
twine==3.3.0
urllib3==1.26.2
virtualenv==20.2.2
webencodings==0.5.1
......@@ -16,13 +16,17 @@ with open(os.path.join(here, 'README.rst')) as f:
setup(
name="python-units",
packages=find_packages(),
version="0.1.2.post1",
version="0.1.3",
author="Paul K. Korir, PhD",
author_email="[email protected]",
url="https://bacculus.dev/paulkorir/units",
url="https://bacculus.dev/paulkorir/python-units",
description="Python library to represent numbers with units",
long_description=long_description,
long_description_content_type='text/x-rst; charset=UTF-8',
license="GNU GPL v3.0",
keywords="units",
classifiers=[
"Programming Language :: Python :: 2.7",
"Programming Language :: Python :: 3"
]
)
[tox]
envlist = py27, py35, py36, py37, py38, py39
[testenv]
deps =
pytest
pytest-cov
commands =
; pip install --upgrade --no-cache-dir pip
pytest --cov=./units ./units/tests.py
\ No newline at end of file
......@@ -64,6 +64,11 @@ object.__hex__(self)
currency and special cases e.g. £ 32 per person instead of 32 £·person^-1 !!!
"""
if sys.version_info[0] >= 3:
long = int
else:
pass
class UnitsError(Exception):
"""Units Error exception
......@@ -79,7 +84,7 @@ class BaseUnit(object):
"""Base class"""
def __init__(self):
self.__unit_dict = {
self._unit_dict = {
'A': 0,
'cd': 0,
'K': 0,
......@@ -95,11 +100,11 @@ class BaseUnit(object):
The base units are the Systeme International (SI) units
"""
return self.__unit_dict
return self._unit_dict
@unit_dict.setter
def unit_dict(self, unit_dict):
self.__unit_dict = unit_dict
self._unit_dict = unit_dict
def __eq__(self, unit2):
if self.unit_dict == unit2.unit_dict:
......@@ -168,16 +173,16 @@ class DerivedUnit(BaseUnit):
def __init__(self, *args, **kwargs):
super(DerivedUnit, self).__init__(*args, **kwargs)
self.__name = None
self._name = None
@property
def name(self):
"""Unit name"""
return self.__name
return self._name
@name.setter
def name(self, name):
self.__name = name
self._name = name
@property
def full_units(self):
......@@ -203,7 +208,9 @@ class DerivedUnit(BaseUnit):
return obj
def __str__(self):
return self.name
if self.name:
return self.name
return self.full_units
class UnitOperandError(Exception):
......@@ -252,29 +259,28 @@ class Unit(object):
def __init__(self, value, unit=None):
assert isinstance(unit, BaseUnit) or unit is None
assert isinstance(value, int) or isinstance(value, float) or isinstance(value, complex) or isinstance(value,
long) # long, double? etc.
self.__value = value
self.__unit = unit
assert isinstance(value, int) or isinstance(value, float) or isinstance(value, complex) or isinstance(value, long) # long, double? etc.
self._value = value
self._unit = unit
@property
def value(self):
"""Numeric value"""
return self.__value
return self._value
@value.setter
def value(self, value):
self.__value = value
self._value = value
@property
def unit(self):
"""Unit"""
return self.__unit
return self._unit
@unit.setter
def unit(self, unit):
if isinstance(unit, unit):
self.__unit = unit
self._unit = unit
else:
raise UnitsError('units mismatch: {} and {}'.format(self.unit, type(unit)))
......@@ -297,10 +303,10 @@ class Unit(object):
758 Pa
758 kg·m^-1·s^-2
"""
if not isinstance(self.__unit, SIUnit):
return '{} {}'.format(self.value, self.__unit.full_units)
if not isinstance(self._unit, SIUnit):
return '{} {}'.format(self.value, self._unit.full_units)
else:
return '{} {}'.format(self.value, self.__unit)
return '{} {}'.format(self.value, self._unit)
def __add__(self, unit2):
if isinstance(unit2, Unit):
......@@ -329,9 +335,9 @@ class Unit(object):
def __mul__(self, unit2):
if isinstance(unit2, Unit):
return Unit(self.value * unit2.value, self.unit * unit2.unit)
elif isinstance(unit2, int) or isinstance(unit2, float) or isinstance(unit2, long) or isinstance(unit2,
complex) or isinstance(
unit2, oct) or isinstance(unit2, hex):
elif isinstance(unit2, int) or isinstance(unit2, float) or \
isinstance(unit2, long) or isinstance(unit2, complex) \
or isinstance(unit2, oct) or isinstance(unit2, hex):
return Unit(self.value * unit2, self.unit)
# else:
# raise UnitOperandError('not object of type unit: {}'.format(type(unit2)))
......@@ -446,7 +452,7 @@ class Unit(object):
raise TypeError('invalid conversion from Unit object to long')
def __str__(self):
return '{} {}'.format(self.value, self.__unit).strip(' ')
return '{} {}'.format(self.value, self._unit).strip(' ')
# def __repr__(self):
# return '{} {}'.format(self.value, self.__unit)
......
......@@ -148,6 +148,13 @@ class TestUnits(unittest.TestCase):
# self.assertEqual(str(long_unit(Unit(rnum, metre))), '{} m'.format(long(rnum)))
self.assertEqual(str(complex_unit(Unit(rnum, metre))), '{} m'.format(complex(rnum)))
def test_operation_derived(self):
"""Operations on derived units"""
v1 = Unit(random.random(), newton)
v2 = Unit(random.random(), radian)
result = v1 / v2
self.assertIsInstance(str(result), str) # otherwise we get a typeerror
if __name__ == "__main__":
unittest.main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment