././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1622038872.4533162 py-moneyed-2.0/0000755000175100001710000000000000000000000013001 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/CHANGES.rst0000644000175100001710000001407100000000000014606 0ustar00runnerdocker============ Change log ============ Significant or incompatible changes listed here. Unreleased - TBA ---------------- 2.0 (2021-05-26) ---------------- * Dropped support for Python 2.7 and 3.5 and PyPy 2. * Added pyupgrade pre-commit hook. * Added black pre-commit hook and reformatted codebase. * Updated pre-commit hooks. * Replaced custom flake8, isort and check-manifest Github Action jobs with a generic pre-commit job. * Dropped the ``moneyed.localization`` module that was deprecated and announced for removal in 1.0. * Added type hints along with a mypy pre-commit hook. * Added action for building and publishing releases, along with the check-github-workflows pre-commit hook for validating Github Action workflow files. * Removed undocumented ``DEFAULT_CURRENCY`` and ``DEFAULT_CURRENCY_CODE`` constants, and change to make instantiating ``Money`` without providing a currency a type error. This used to result in an object with a made-up ``"XYZ"`` currency, which could lead to surprising behaviors and bugs. * Added ``zero`` property to ``Currency`` to conveniently access the zero value of a given currency. * Moved to use setuptool's declarative packaging config and PEP 517 isolated builds. * Removed requirements files and instead specified test requirements using extras. 1.2 (2021-02-23) ---------------- * ``Money.__add__`` returns ``NotImplemented`` instead of raising an exception when another operand has unsupported type. 1.1 (2021-01-15) ---------------- * Changed the ``numeric`` attribute values to ``None`` for currencies that don't have assigned ISO numeric codes: ``IMP``, ``TVD``, ``XFO``, ``XFU``. * Restored the previous definition for the ``XXX`` currency, including its ``name`` and ``countries`` attributes. * Fixed ``get_currency`` returning obsolete currencies. 1.0 (2021-01-09) ---------------- * Dropped official support for Python 2.6, 3.2, 3.3, 3.4 (mainly because our test tools don't support them any more). * Added support for getting amount in sub units (fixed point) * Format ``Money`` instances using CLDR and Babel. This is a large change with lots of parts. Many thanks to @pooyamb for all the hard work that went into this and other related changes. * Added new ``moneyed.l10n`` module, containing a new ``format_money`` function. This is a very thin wrapper around `babel.numbers.format_currency `_ and has all the same options. This allows us to get the official CLDR formats for currencies, in all the different locales. See docs in README. Note especially that you need to specify ``locale`` (e.g. ``locale="en_US"``), or you will get the ``LC_NUMERIC`` default. * Deprecated the ``format_money`` function in ``moneyed.localization``. There is no immediate plan to remove, but it should not be relied on. Also, this function relies on our own manually entered data for formatting of currencies in different locales. This data is very incomplete and will not be updated any more. So you need to use ``moneyed.l10n.format_money`` instead now. If you were relying on the ``decimal_places`` argument to the old function, there is no exact equivalent in the new ``format_money`` function, but see the ``decimal_quantization`` option (documented in `babel.numbers.format_currency `_) * ``Money.__str__`` (``Money.__unicode__`` on Python 2) now uses new ``format_money`` with the default locale ``LC_NUMERIC``, which can produce different results from the old function. Use the new ``format_money`` to control output. * On Python 2, ``Money.__str__`` (bytestring) output has changed to be more basic. You should use the new ``format_money`` function to control output. * Get currency names from Babel data. Several changes, including: * For all built-in currencies, ``Currency.name`` now comes from Babel ("en_US" locale). This means there have been various corrections to currency names. If you pass a non-None ``name`` to the ``Currency`` constructor, you can still specify any name you want. * ``Currency.get_name(locale)`` has been added. * Get currency 'countries' from Babel data. Several changes, including: * ``Currency.countries`` now sources from Babel, so some names may be different. * ``Currency.country_codes`` has been added. * ``Currency.countries`` is deprecated, because it is not the most useful form for the data (e.g. upper cased strings, and names in US English only). It is recommended to use ``Currency.country_codes`` and convert to names using ``get_country_name``. * Changed the repr of ``Money`` so that ``eval(repr(money_object) == money_object`` (at least in some environments, and most of the typical ones). See `Python docs on __repr__ `_ for rationale. Thanks `@davidtvs `_. This could be backwards incompatible if you were relying on the old output of ``repr()``. * Added ``list_all_currencies()`` utility function. 0.8 (2018-11-19) ---------------- * ``Money.round([ndigits])`` added. Uses ``decimal.ROUND_HALF_EVEN`` by default, but this can be overridden by setting ``rounding`` in the ``decimal`` context before calling ``Money.round()``. * Various fixes/additions for different locales * Division support on Python 2 * DEFAULT locale is now used as a fallback to return a currency symbol if your chosen locale has no symbol set for that currency, rather than just returning the currency code. 0.7 (2017-05-08) ---------------- * ``Money.__str__`` changed under Python 2 to use only ASCII characters. This means that currency codes, rather than symbols, are used. * Lots of additional locales supported out of the box. * Python 3.5 supported * Fixed #70 - format_money error when the locale is not in the formatting definitions: the default is not used. * Various other bug fixes 0.6 and earlier --------------- * See VCS logs. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/CONTRIBUTING.rst0000644000175100001710000000345500000000000015451 0ustar00runnerdockerContributing to py-moneyed ========================== If you would like to contribute to py-moneyed, the recommended workflow is: 1. First raise an issue on GitHub for any proposal or idea that might be controversial and get feedback from the maintainers. If you have something that is an obvious bug (a typo in the docs, for example), you can skip this step. 2. Fork the project and checkout your fork onto your development machine. 3. Create a virtualenv of some kind for development (venv_, virtualenv_ or virtualenvwrapper_) and install py-moneyed into it:: python setup.py develop 4. Optional, but highly recommended to save time later - install `pre-commit `_ hooks:: pip install pre-commit pre-commit install 5. Create a git branch for your changes, starting from ``master`` 6. Fix the bug or implement your changes, being sure to: 1. Add tests and docs 2. Run the test suite (below) 7. Push your changes to your GitHub repo and submit a pull request. Testing ------- To run the test suite, first install tox (into your virtualenv):: pip install tox Run the tests using tox:: tox -e py39 You can run the test suite on all supported environments using tox_ (recommended). If you do not have all versions of Python that are used in testing, you can use pyenv_ to install them, and you may benefit from the additional plugin pyenv-implict_. The py-moneyed package is tested against Python 3.6 - 3.9 and PyPy 3. .. _tox: https://tox.readthedocs.io/en/latest/ .. _pyenv: https://github.com/pyenv/pyenv .. _pyenv-implict: https://github.com/concordusapps/pyenv-implict .. _venv: https://docs.python.org/3/library/venv.html .. _virtualenv: https://virtualenv.pypa.io/en/stable/ .. _virtualenvwrapper: https://virtualenvwrapper.readthedocs.io/en/latest/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/CONTRIBUTORS0000644000175100001710000000050300000000000014657 0ustar00runnerdockerpy-moneyed was started by Kai Wu in July 2010 and publicly released in February 2011. Jacob Hansson (jacob@voltvoodoo.com) contributed a better currency formatting implementation, and various patches, in May 2011. Wojciech Banas added compatibility with multiple versions of Python, including Python 3.x, in August 2013. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/LICENSE0000644000175100001710000000274300000000000014014 0ustar00runnerdockerCopyright (c) 2011 Kai Wu, k@limist.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the names of the copyright holders of this software, nor its contributors, may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/MANIFEST.in0000644000175100001710000000041000000000000014532 0ustar00runnerdockerinclude *.rst include CONTRIBUTORS include LICENSE include src/**/py.typed recursive-include docs *.bat recursive-include docs *.py recursive-include docs *.rst recursive-include docs Makefile recursive-exclude tests * exclude *.yaml exclude *.yml exclude tox.ini ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1622038872.4533162 py-moneyed-2.0/PKG-INFO0000644000175100001710000000544000000000000014101 0ustar00runnerdockerMetadata-Version: 2.1 Name: py-moneyed Version: 2.0 Summary: Provides Currency and Money classes for use in your Python code. Home-page: UNKNOWN Author: Kai Author-email: k@limist.com Maintainer: Dmitry Dygalo Maintainer-email: dadygalo@gmail.com License: BSD Project-URL: Homepage, http://github.com/py-moneyed/py-moneyed Project-URL: Documentation, https://py-moneyed.readthedocs.io/en/latest/ Keywords: money currency class abstraction Platform: any Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Development Status :: 6 - Mature Classifier: Environment :: Other Environment Classifier: Intended Audience :: Developers Classifier: Topic :: Office/Business :: Financial Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.6 Description-Content-Type: text/x-rst Provides-Extra: tests Provides-Extra: type-tests License-File: LICENSE .. image:: https://github.com/py-moneyed/py-moneyed/workflows/build/badge.svg :target: https://github.com/py-moneyed/py-moneyed/actions?query=workflow%3Abuild :alt: Build Status .. image:: https://badge.fury.io/py/py-moneyed.svg :target: https://pypi.org/project/py-moneyed/ :alt: Latest PyPI version .. image:: https://readthedocs.org/projects/py-moneyed/badge/?version=latest :target: http://py-moneyed.readthedocs.io/en/latest/?badge=latest Overview ======== The need to represent instances of money frequently arises in software development, particularly any financial/economics software. To address that need, the py-moneyed package provides the classes of Money and Currency, at a level more useful than just using Python's Decimal class, or ($DEITY forbid) the float primitive. The package is meant to be stand-alone and used directly, or be subclassed further. py-moneyed is BSD-licensed. Quick start ----------- To install:: pip install py-moneyed Use: .. sourcecode:: python from moneyed import Money, USD five_dollars = Money(5, USD) You then use ``Money`` objects as if they were numbers, and they behave sensibly. See `docs `_ for more information (or the ``docs/`` folder). History ------- Some of the py-moneyed code was first derived from python-money available via this URL: http://code.google.com/p/python-money/ Due to inactivity, it was forked by @limist in 2010 and later moved to the py-moneyed organization. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/README.rst0000644000175100001710000000276200000000000014477 0ustar00runnerdocker.. image:: https://github.com/py-moneyed/py-moneyed/workflows/build/badge.svg :target: https://github.com/py-moneyed/py-moneyed/actions?query=workflow%3Abuild :alt: Build Status .. image:: https://badge.fury.io/py/py-moneyed.svg :target: https://pypi.org/project/py-moneyed/ :alt: Latest PyPI version .. image:: https://readthedocs.org/projects/py-moneyed/badge/?version=latest :target: http://py-moneyed.readthedocs.io/en/latest/?badge=latest Overview ======== The need to represent instances of money frequently arises in software development, particularly any financial/economics software. To address that need, the py-moneyed package provides the classes of Money and Currency, at a level more useful than just using Python's Decimal class, or ($DEITY forbid) the float primitive. The package is meant to be stand-alone and used directly, or be subclassed further. py-moneyed is BSD-licensed. Quick start ----------- To install:: pip install py-moneyed Use: .. sourcecode:: python from moneyed import Money, USD five_dollars = Money(5, USD) You then use ``Money`` objects as if they were numbers, and they behave sensibly. See `docs `_ for more information (or the ``docs/`` folder). History ------- Some of the py-moneyed code was first derived from python-money available via this URL: http://code.google.com/p/python-money/ Due to inactivity, it was forked by @limist in 2010 and later moved to the py-moneyed organization. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/RELEASE.rst0000644000175100001710000000110400000000000014607 0ustar00runnerdockerRelease process =============== * Check that all tests are passing on GitHub Actions: https://github.com/py-moneyed/py-moneyed/actions?query=workflow%3Abuild+branch%3Amaster * Change version number in: * setup.py * docs/conf.py * Fix 'CHANGES.rst' so the top section says "[new version number] [date]" * Commit to VCS * Tag the release e.g.:: git tag v0.7 git push upstream --tags Post release ~~~~~~~~~~~~ * Add new section to CHANGES.rst - "[next version number] (unreleased)" * Add next version number plus "-dev" suffix in ``setup.py``, ``docs/conf.py`` ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1622038872.449316 py-moneyed-2.0/docs/0000755000175100001710000000000000000000000013731 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/Makefile0000644000175100001710000000117200000000000015372 0ustar00runnerdocker# Minimal makefile for Sphinx documentation # # You can set these variables from the command line, and also # from the environment for the first two. SPHINXOPTS ?= SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build # Put it first so that "make" without argument is like "make help". help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) .PHONY: help Makefile # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/conf.py0000644000175100001710000000357300000000000015240 0ustar00runnerdocker# Configuration file for the Sphinx documentation builder. # # This file only contains a selection of the most common options. For a full # list see the documentation: # https://www.sphinx-doc.org/en/master/usage/configuration.html # -- Path setup -------------------------------------------------------------- # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # # import os # import sys # sys.path.insert(0, os.path.abspath('.')) # -- Project information ----------------------------------------------------- project = "py-moneyed" copyright = "2021, Kai Wu" author = "Kai Wu" # The full version, including alpha/beta/rc tags release = "2.0" # -- General configuration --------------------------------------------------- # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [] # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # -- Options for HTML output ------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. # # html_theme = 'default' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = ['_static'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/conftest.py0000644000175100001710000000066700000000000016141 0ustar00runnerdockerfrom typing import Dict import pytest from moneyed import USD, Money @pytest.fixture(autouse=True) def add_entities(doctest_namespace: Dict[str, object]) -> None: """ Inserts entities into doctest namespaces so that imports don't have to be added to all examples. https://docs.pytest.org/en/stable/doctest.html#doctest-namespace-fixture """ doctest_namespace["Money"] = Money doctest_namespace["USD"] = USD ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/contributing.rst0000644000175100001710000000004100000000000017165 0ustar00runnerdocker.. include:: ../CONTRIBUTING.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/formatting.rst0000644000175100001710000000210300000000000016631 0ustar00runnerdockerFormatting ========== You can print :class:`Money` object as follows: .. code-block:: python >>> from moneyed.l10n import format_money >>> format_money(Money(10, USD), locale='en_US') '$10.00' Note that you need to specify ``locale`` or you will get the system default, which will probably not be what you want. For this reason, it is recommended to always provide the ``locale`` argument, and you may well want to add your own wrappers around this function to supply your project specific defaults. This function is a thin wrapper around `babel.numbers.format_currency `_. See those docs for other arguments that can be specified to control the formatting of the number. By default, Babel will apply definitions of how to format currencies that have been derived from the large `CLDR database `_. If you do ``str()`` on a ``Money`` object, you will get the same behaviour as ``format_money()``, but with no options supplied, so you will get the system default locale. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/history.rst0000644000175100001710000000003400000000000016161 0ustar00runnerdocker.. include:: ../CHANGES.rst ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/index.rst0000644000175100001710000000060400000000000015572 0ustar00runnerdockerWelcome to py-moneyed's documentation! ====================================== These are the docs for py-moneyed |release|. Check the :doc:`/history` for significant changes. .. toctree:: :maxdepth: 2 :caption: Contents: installation usage formatting contributing history Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/installation.rst0000644000175100001710000000015300000000000017163 0ustar00runnerdocker============ Installation ============ py-moneyed can be installed with pip:: pip install py-moneyed ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/make.bat0000644000175100001710000000143300000000000015337 0ustar00runnerdocker@ECHO OFF pushd %~dp0 REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set SOURCEDIR=. set BUILDDIR=_build if "%1" == "" goto help %SPHINXBUILD% >NUL 2>NUL if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% goto end :help %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% :end popd ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/docs/usage.rst0000644000175100001710000000722400000000000015574 0ustar00runnerdockerUsage ===== .. currentmodule:: moneyed The :class:`Money` class is instantiated with: - An amount which can be of type int, string, float, or Decimal. It will be converted to a Decimal internally. Therefore, it is best to avoid float objects, since they do not convert losslessly to Decimal. - A currency, as a :class:`Currency` object, or as a string which is a three-capital-letters ISO currency code (e.g. ``'USD'``, ``'EUR'`` etc), which will be converted to a :class:`Currency` object. For example, .. code-block:: python from moneyed import Money sale_price_today = Money(amount='99.99', currency='USD') You then use :class:`Money` instances as a normal number. The Money class provides operators with type checking, matching currency checking, and sensible dimensional behavior, e.g. you cannot multiply two Money instances, nor can you add a Money instance to a non-Money number; dividing a Money instance by another results in a Decimal value, etc. The :class:`Currency` class is also provided. All ISO 4217 currencies are available by importing from the ``moneyed`` module by their 3-letter code, as pre-built :class:`Currency` objects. You can also pass in the arguments to :class:`Money` as positional arguments. So you can also write: .. code-block:: python >>> from moneyed import Money, USD >>> price = Money('19.50', USD) >>> price Money('19.50', 'USD') >>> price.amount Decimal('19.50') >>> price.currency USD >>> price.currency.code 'USD' If you want to get the amount in sub units (ISO 4127 compatible) you can do: .. code-block:: python >>> from moneyed import Money, USD >>> price = Money('19.50', USD) >>> price.get_amount_in_sub_unit() 1950 >>> price = Money('123.456', USD) >>> price.get_amount_in_sub_unit() 12345 Currency instances have a ``zero`` property for convenience. It returns a cached ``Money`` instance of the currency. This can be helpful for instance when summing up a list of money instances using the builtin ``sum()``. .. code-block:: python >>> from moneyed import Money, USD >>> currency = USD >>> items = (Money('19.99', currency), Money('25.00', currency)) >>> sum(items, currency.zero) Money('44.99', 'USD') >>> sum((), currency.zero) Money('0', 'USD') Search by Country Code ---------------------- In order to find the ISO code associated with a country, the function :func:`get_currencies_of_country` can be used. This function takes the ISO country code (case insensitive) as the argument and returns the associated currency object(s) in a list. If a country with the given name is not found the function returns an empty list. The code below demonstrates this: .. code-block:: python >>> from moneyed import get_currencies_of_country >>> get_currencies_of_country("IN") [INR] >>> get_currencies_of_country("BO") [BOB, BOV] >>> get_currencies_of_country("XX") [] Get country names ----------------- ``Currency.country_codes`` returns a list of `ISO 3166 country codes `_. You can convert these to names using the function ``get_country_name``, which must be passed a ISO 2-letter code and a locale code: .. code-block:: python >>> from moneyed import ZMW, get_country_name >>> ZMW.country_codes ['ZM'] >>> get_country_name('ZM', 'en') 'Zambia' List all currencies ------------------- You can get all installed currencies as below: .. code-block:: python >>> from moneyed import list_all_currencies >>> list_all_currencies() [ADP, AED, AFA, ...] The result is a list of :class:`Currency` objects, sorted by ISO code. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/pyproject.toml0000644000175100001710000000014200000000000015712 0ustar00runnerdocker[build-system] requires = ["setuptools>=57.0.0", "wheel"] build-backend = "setuptools.build_meta" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1622038872.4533162 py-moneyed-2.0/setup.cfg0000644000175100001710000000452700000000000014632 0ustar00runnerdocker[metadata] name = py-moneyed version = 2.0 description = Provides Currency and Money classes for use in your Python code. long_description = file: README.rst long_description_content_type = text/x-rst author = Kai author_email = k@limist.com maintainer = Dmitry Dygalo maintainer_email = dadygalo@gmail.com keywords = money currency class abstraction license = BSD platforms = any classifiers = Programming Language :: Python Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 Programming Language :: Python :: Implementation :: CPython Programming Language :: Python :: Implementation :: PyPy License :: OSI Approved :: BSD License Operating System :: OS Independent Development Status :: 6 - Mature Environment :: Other Environment Intended Audience :: Developers Topic :: Office/Business :: Financial Topic :: Software Development :: Libraries :: Python Modules project_urls = Homepage = http://github.com/py-moneyed/py-moneyed Documentation = https://py-moneyed.readthedocs.io/en/latest/ [options] packages = find: package_dir = =src include_package_data = True python_requires = >=3.6 install_requires = babel>=2.8.0 typing-extensions>=3.7.4.3 [options.packages.find] where = src [options.extras_require] tests = pytest>=2.3.0 tox>=1.6.0 type-tests = pytest>=2.3.0 pytest-mypy-plugins mypy>=0.812 [flake8] max-line-length = 119 [isort] profile = black [tool:pytest] addopts = --doctest-modules --doctest-glob='*.rst' -Werror python_files = test_*.py *_test.py tests.py testpaths = tests norecursedirs = .git .tox dist build .mypy_cache [mypy] python_version = 3.6 show_error_codes = True pretty = True files = src/, tests/ ignore_missing_imports = False no_implicit_optional = True strict_equality = True strict_optional = True check_untyped_defs = True disallow_incomplete_defs = True disallow_untyped_defs = True disallow_untyped_calls = True disallow_untyped_decorators = True disallow_subclassing_any = True warn_unused_configs = True warn_redundant_casts = True warn_unused_ignores = True warn_return_any = True warn_unreachable = True [mypy-tests.test_l10n] disallow_untyped_defs = False [mypy-tests.test_moneyed_classes] ignore_errors = True [mypy-babel.*] ignore_missing_imports = True [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/setup.py0000755000175100001710000000007500000000000014520 0ustar00runnerdocker#!/usr/bin/env python import setuptools setuptools.setup() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1622038872.445316 py-moneyed-2.0/src/0000755000175100001710000000000000000000000013570 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1622038872.449316 py-moneyed-2.0/src/moneyed/0000755000175100001710000000000000000000000015230 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/src/moneyed/__init__.py0000644000175100001710000000003700000000000017341 0ustar00runnerdockerfrom .classes import * # NOQA ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/src/moneyed/classes.py0000644000175100001710000006041500000000000017245 0ustar00runnerdockerimport warnings from decimal import Decimal from typing import Any, Dict, List, NoReturn, Optional, TypeVar, Union, overload from babel import Locale from babel.core import get_global from typing_extensions import Final, Protocol from .l10n import format_money from .utils import cached_property def force_decimal(amount: object) -> Decimal: """Given an amount of unknown type, type cast it to be a Decimal.""" if not isinstance(amount, Decimal): return Decimal(str(amount)) return amount class Currency: """ A Currency represents a form of money issued by governments, and used in one or more states/countries. A Currency instance encapsulates the related data of: the ISO currency/numeric code, a canonical name, and countries the currency is used in. """ def __init__( self, code: str = "", numeric: Optional[str] = None, sub_unit: int = 1, name: Optional[str] = None, countries: Optional[List[str]] = None, ) -> None: self.code: Final = code self.numeric: Final = numeric self.sub_unit: Final = sub_unit self._name: Final = name self._countries: Final = countries def __hash__(self) -> int: return hash(self.code) def __eq__(self, other: object) -> bool: return ( type(self) is type(other) and self.code == other.code # type: ignore[attr-defined] ) def __ne__(self, other: object) -> bool: return not self.__eq__(other) def __repr__(self) -> str: return self.code def __lt__(self, other: "Currency") -> bool: return self.code < other.code def __le__(self, other: "Currency") -> bool: return self.code <= other.code @cached_property def name(self) -> str: """ Name of the currency in US locale. For backwards compat. Consider using get_name() instead, or babel.numbers.get_currency_name() """ if self._name is not None: return self._name return self.get_name("en_US") def get_name(self, locale: str, count: Optional[int] = None) -> str: from babel.numbers import get_currency_name return get_currency_name( # type: ignore[no-any-return] self.code, locale=locale, count=count, ) @cached_property def zero(self) -> "Money": return Money(0, self) @cached_property def countries(self) -> List[str]: """ List of country names, uppercased and in US locale, where the currency is used at present. DEPRECATED. Use `.country_codes` instead, and get_country_name() to convert these to a country name in your desired locale. """ if self._countries is not None: return self._countries return [ get_country_name(country_code, "en_US").upper() for country_code in self.country_codes ] @cached_property def country_codes(self) -> List[str]: """ List of current country codes for the currency. """ return [ territory.upper() for territory, currencies in get_global("territory_currencies").items() for currency_code, start, end, is_tender in currencies if end is None and currency_code == self.code ] def get_country_name(country_code: str, locale: str) -> str: return Locale.parse(locale).territories[country_code] # type: ignore[no-any-return] class MoneyComparisonError(TypeError): # This exception was needed often enough to merit its own # Exception class. def __init__(self, other: object) -> None: assert not isinstance(other, Money) self.other = other def __str__(self) -> str: return f"Cannot compare instances of Money and {self.other.__class__.__name__}" class CurrencyDoesNotExist(Exception): def __init__(self, code: Optional[str]) -> None: super().__init__(f"No currency with code {code} is defined.") # This TypeVar is used for methods on Money that return self, so that subclasses become # accurately typed as returning instances of the subclass, not Money itself. M = TypeVar("M", bound="Money") class SupportsNeg(Protocol): def __neg__(self) -> Any: ... class Money: """ A Money instance is a combination of data - an amount and a currency - along with operators that handle the semantics of money operations in a better way than just dealing with raw Decimal or ($DEITY forbid) floats. """ # Overload __init__ to make omitting currency an error that is discoverable through # static type checking. To explain the two signatures: the first one allows omitting # the amount if currency is given as a key-word argument. The second signature # allows calls where both values are given, either as key-word or positional # arguments. As an argument with a default value cannot be followed by one without, # the implementation defines `None` as default for currency, but raises a TypeError # for that case. @overload def __init__(self, amount: object = ..., *, currency: Union[str, Currency]) -> None: ... @overload def __init__(self, amount: object, currency: Union[str, Currency]) -> None: ... def __init__( self, amount: object = Decimal("0.0"), currency: Union[str, Currency, None] = None, ) -> None: if currency is None: raise TypeError( "__init__() missing 1 required positional argument: 'currency'" ) self.amount: Final = ( amount if isinstance(amount, Decimal) else Decimal(str(amount)) ) self.currency: Final = ( currency if isinstance(currency, Currency) else get_currency(str(currency).upper()) ) def __repr__(self) -> str: return f"Money('{self.amount}', '{self.currency}')" def __str__(self) -> str: return format_money(self) def __hash__(self) -> int: return hash((self.amount, self.currency)) def __pos__(self: M) -> M: return self.__class__( amount=self.amount, currency=self.currency, ) def __neg__(self: M) -> M: return self.__class__( amount=-self.amount, currency=self.currency, ) def __add__(self: M, other: object) -> M: if other == 0: # This allows things like 'sum' to work on list of Money instances, # just like list of Decimal. return self if not isinstance(other, Money): return NotImplemented if self.currency == other.currency: return self.__class__( amount=self.amount + other.amount, currency=self.currency, ) raise TypeError( "Cannot add or subtract two Money instances with different currencies." ) def __sub__(self: M, other: SupportsNeg) -> M: return self.__add__(-other) def __rsub__(self: M, other: object) -> M: return (-self).__add__(other) def __mul__(self: M, other: object) -> M: if isinstance(other, Money): raise TypeError("Cannot multiply two Money instances.") else: if isinstance(other, float): warnings.warn( "Multiplying Money instances with floats is deprecated", DeprecationWarning, ) return self.__class__( amount=(self.amount * force_decimal(other)), currency=self.currency, ) def __truediv__(self: M, other: object) -> Union[M, Decimal]: if isinstance(other, Money): if self.currency != other.currency: raise TypeError("Cannot divide two different currencies.") return self.amount / other.amount else: if isinstance(other, float): warnings.warn( "Dividing Money instances by floats is deprecated", DeprecationWarning, ) return self.__class__( amount=(self.amount / force_decimal(other)), currency=self.currency, ) def __rtruediv__(self, other: object) -> NoReturn: raise TypeError("Cannot divide non-Money by a Money instance.") def round(self: M, ndigits: Optional[int] = 0) -> M: """ Rounds the amount using the current ``Decimal`` rounding algorithm. """ if ndigits is None: ndigits = 0 return self.__class__( amount=self.amount.quantize(Decimal("1e" + str(-ndigits))), currency=self.currency, ) def __abs__(self: M) -> M: return self.__class__( amount=abs(self.amount), currency=self.currency, ) def __bool__(self) -> bool: return bool(self.amount) def __rmod__(self: M, other: object) -> M: """ Calculate percentage of an amount. The left-hand side of the operator must be a numeric value. Example: >>> money = Money(200, 'USD') >>> 5 % money Money('10', 'USD') """ if isinstance(other, Money): raise TypeError("Invalid __rmod__ operation") else: if isinstance(other, float): warnings.warn( "Calculating percentages of Money instances using floats is deprecated", DeprecationWarning, ) return self.__class__( amount=(Decimal(str(other)) * self.amount / 100), currency=self.currency, ) __radd__ = __add__ __rmul__ = __mul__ # _______________________________________ # Override comparison operators def __eq__(self, other: object) -> bool: return ( isinstance(other, Money) and self.amount == other.amount and self.currency == other.currency ) def __ne__(self, other: object) -> bool: result = self.__eq__(other) return not result def __lt__(self, other: object) -> bool: if not isinstance(other, Money): raise MoneyComparisonError(other) if self.currency == other.currency: return self.amount < other.amount else: raise TypeError("Cannot compare Money with different currencies.") def __gt__(self, other: object) -> bool: if not isinstance(other, Money): raise MoneyComparisonError(other) if self.currency == other.currency: return self.amount > other.amount else: raise TypeError("Cannot compare Money with different currencies.") def __le__(self, other: object) -> bool: return self < other or self == other def __ge__(self, other: object) -> bool: return self > other or self == other def get_amount_in_sub_unit(self) -> int: return int(self.currency.sub_unit * self.amount) # ____________________________________________________________________ # Definitions of ISO 4217 Currencies # Source: http://www.iso.org/iso/support/faqs/faqs_widely_used_standards/widely_used_standards_other/currency_codes/currency_codes_list-1.htm # noqa CURRENCIES: Dict[str, Currency] = {} CURRENCIES_BY_ISO: Dict[str, Currency] = {} def add_currency( code: str, numeric: Optional[str], sub_unit: int = 1, name: Optional[str] = None, countries: Optional[List[str]] = None, ) -> Currency: currency = Currency( code=code, numeric=numeric, sub_unit=sub_unit, name=name, countries=countries ) CURRENCIES[code] = currency # No lookup by numeric code for currencies without numeric codes if numeric is not None: CURRENCIES_BY_ISO[numeric] = currency return currency @overload def get_currency(code: str) -> Currency: ... @overload def get_currency(*, iso: Union[int, str]) -> Currency: ... def get_currency( code: Optional[str] = None, iso: Union[int, str, None] = None ) -> Currency: try: if iso: return CURRENCIES_BY_ISO[str(iso)] return CURRENCIES[code] # type: ignore[index] except KeyError: raise CurrencyDoesNotExist(code) def get_currencies_of_country(country_code: str) -> List[Currency]: """ Returns list with currency object(s) given the country's ISO-2 code. Raises a CountryDoesNotExist exception if the country is not found. country : str The full name of the country to be searched for. """ country_code = country_code.upper() return sorted( [ currency for currency in CURRENCIES.values() if country_code in currency.country_codes ] ) def list_all_currencies() -> List[Currency]: return sorted(CURRENCIES.values(), key=lambda c: c.code) # The order of registration is important because we want active currencies to be available via `get_currency`. # For this reason, we have obsolete currencies first, and then they may be overridden by active ones # Obsolete currencies ADP = add_currency("ADP", "020") AFA = add_currency("AFA", "004", 100) ALK = add_currency("ALK", "008") AON = add_currency("AON", "024") AOR = add_currency("AOR", "982") ARA = add_currency("ARA", "032", 100) ARP = add_currency("ARP", "032", 100) ATS = add_currency("ATS", "040", 100) AZM = add_currency("AZM", "031", 100) BAD = add_currency("BAD", "070", 100) BEF = add_currency("BEF", "056", 100) BGL = add_currency("BGL", "100", 100) BRC = add_currency("BRC", "076", 100) BRE = add_currency("BRE", "076", 100) BRN = add_currency("BRN", "076", 100) BRR = add_currency("BRR", "987", 100) BYR = add_currency("BYR", "974") CLE = add_currency("CLE", "152") CSD = add_currency("CSD", "891", 100) CSK = add_currency("CSK", "200") CYP = add_currency("CYP", "196", 100) DDM = add_currency("DDM", "278") DEM = add_currency("DEM", "276", 100) ECS = add_currency("ECS", "218") ECV = add_currency("ECV", "983", 100) EEK = add_currency("EEK", "233", 100) ESA = add_currency("ESA", "996") ESB = add_currency("ESB", "995") ESP = add_currency("ESP", "020") FIM = add_currency("FIM", "246", 100) FRF = add_currency("FRF", "250", 100) GHC = add_currency("GHC", "288", 100) GRD = add_currency("GRD", "300", 100) GWP = add_currency("GWP", "624", 100) HRD = add_currency("HRD", "191", 100) IEP = add_currency("IEP", "372", 100) ITL = add_currency("ITL", "380") LTL = add_currency("LTL", "440", 100) LUF = add_currency("LUF", "442", 100) LVL = add_currency("LVL", "428", 100) MGF = add_currency("MGF", "450") MLF = add_currency("MLF", "466") MRO = add_currency("MRO", "478", 100) MTL = add_currency("MTL", "470", 100) MZM = add_currency("MZM", "508", 100) NLG = add_currency("NLG", "528", 100) PEI = add_currency("PEI", "604") PLZ = add_currency("PLZ", "616", 100) PTE = add_currency("PTE", "620") ROL = add_currency("ROL", "642") RUR = add_currency("RUR", "810", 100) SDD = add_currency("SDD", "736", 100) SIT = add_currency("SIT", "705", 100) SKK = add_currency("SKK", "703", 100) SRG = add_currency("SRG", "740", 100) STD = add_currency("STD", "678", 100) TJR = add_currency("TJR", "762") TMM = add_currency("TMM", "795", 100) TPE = add_currency("TPE", "626") TRL = add_currency("TRL", "792") UAK = add_currency("UAK", "804", 100) USS = add_currency("USS", "998", 100) VEB = add_currency("VEB", "862", 100) VEF = add_currency("VEF", "937", 100) VNN = add_currency("VNN", "704") XEU = add_currency("XEU", "954") YDD = add_currency("YDD", "710") YUM = add_currency("YUM", "891", 100) YUN = add_currency("YUN", "890", 100) ZAL = add_currency("ZAL", "991", 100) ZMK = add_currency("ZMK", "894", 100) ZRN = add_currency("ZRN", "180", 100) ZRZ = add_currency("ZRZ", "180", 100) ZWD = add_currency("ZWD", "716", 100) ZWL = add_currency("ZWL", "932", 100) ZWR = add_currency("ZWR", "935", 100) # Further obsolete currencies that don't appear to have ISO 4217 codes AOK = add_currency("AOK", None) ARL = add_currency("ARL", None, 100) ARM = add_currency("ARM", None, 100) BAN = add_currency("BAN", None) BEC = add_currency("BEC", None) BEL = add_currency("BEL", None) BGM = add_currency("BGM", None) BGO = add_currency("BGO", None) BOL = add_currency("BOL", None) BOP = add_currency("BOP", None, 100) BRB = add_currency("BRB", None, 100) BRZ = add_currency("BRZ", None, 100) BUK = add_currency("BUK", None) BYB = add_currency("BYB", None, 100) CNH = add_currency("CNH", None, 100) CNX = add_currency("CNX", None, 100) GEK = add_currency("GEK", None) GNS = add_currency("GNS", None) GQE = add_currency("GQE", None) GWE = add_currency("GWE", None) ILP = add_currency("ILP", None, 100) ILR = add_currency("ILR", None, 100) ISJ = add_currency("ISJ", None, 100) KRH = add_currency("KRH", None) KRO = add_currency("KRO", None) LTT = add_currency("LTT", None, 100) LUC = add_currency("LUC", None) LUL = add_currency("LUL", None) LVR = add_currency("LVR", None, 100) MAF = add_currency("MAF", None, 100) MCF = add_currency("MCF", None, 100) MDC = add_currency("MDC", None) MKN = add_currency("MKN", None) MRU = add_currency("MRU", None, 100) MTP = add_currency("MTP", None) MVP = add_currency("MVP", None) MXP = add_currency("MXP", None) MZE = add_currency("MZE", None, 100) NIC = add_currency("NIC", None, 100) PES = add_currency("PES", None, 100) RHD = add_currency("RHD", None, 100) SDP = add_currency("SDP", None) STN = add_currency("STN", None, 100) SUR = add_currency("SUR", None) UGS = add_currency("UGS", None) UYP = add_currency("UYP", None, 100) UYW = add_currency("UYW", None, 10000) VES = add_currency("VES", None, 100) XRE = add_currency("XRE", None) YUD = add_currency("YUD", None, 100) YUR = add_currency("YUR", None, 100) # Active currencies AED = add_currency("AED", "784", 100) AFN = add_currency("AFN", "971", 100) ALL = add_currency("ALL", "008", 100) AMD = add_currency("AMD", "051", 100) ANG = add_currency("ANG", "532", 100) AOA = add_currency("AOA", "973", 100) ARS = add_currency("ARS", "032", 100) AUD = add_currency("AUD", "036", 100) AWG = add_currency("AWG", "533", 100) AZN = add_currency("AZN", "944", 100) BAM = add_currency("BAM", "977", 100) BBD = add_currency("BBD", "052", 100) BDT = add_currency("BDT", "050", 100) BGN = add_currency("BGN", "975", 100) BHD = add_currency("BHD", "048", 1000) BIF = add_currency("BIF", "108") BMD = add_currency("BMD", "060", 100) BND = add_currency("BND", "096", 100) BOB = add_currency("BOB", "068", 100) BOV = add_currency("BOV", "984", 100) BRL = add_currency("BRL", "986", 100) BSD = add_currency("BSD", "044", 100) BTN = add_currency("BTN", "064", 100) BWP = add_currency("BWP", "072", 100) BYN = add_currency("BYN", "933", 100) BZD = add_currency("BZD", "084", 100) CAD = add_currency("CAD", "124", 100) CDF = add_currency("CDF", "976", 100) CHE = add_currency("CHE", "947", 100) CHF = add_currency("CHF", "756", 100) CHW = add_currency("CHW", "948", 100) CLF = add_currency("CLF", "990", 10000) CLP = add_currency("CLP", "152") CNY = add_currency("CNY", "156", 100) COP = add_currency("COP", "170", 100) COU = add_currency("COU", "970", 100) CRC = add_currency("CRC", "188", 100) CUC = add_currency("CUC", "931", 100) CUP = add_currency("CUP", "192", 100) CVE = add_currency("CVE", "132", 100) CZK = add_currency("CZK", "203", 100) DJF = add_currency("DJF", "262") DKK = add_currency("DKK", "208", 100) DOP = add_currency("DOP", "214", 100) DZD = add_currency("DZD", "012", 100) EGP = add_currency("EGP", "818", 100) ERN = add_currency("ERN", "232", 100) ETB = add_currency("ETB", "230", 100) EUR = add_currency("EUR", "978", 100) FJD = add_currency("FJD", "242", 100) FKP = add_currency("FKP", "238", 100) GBP = add_currency("GBP", "826", 100) GEL = add_currency("GEL", "981", 100) GHS = add_currency("GHS", "936", 100) GIP = add_currency("GIP", "292", 100) GMD = add_currency("GMD", "270", 100) GNF = add_currency("GNF", "324") GTQ = add_currency("GTQ", "320", 100) GYD = add_currency("GYD", "328", 100) HKD = add_currency("HKD", "344", 100) HNL = add_currency("HNL", "340", 100) HRK = add_currency("HRK", "191", 100) HTG = add_currency("HTG", "332", 100) HUF = add_currency("HUF", "348", 100) IDR = add_currency("IDR", "360", 100) ILS = add_currency("ILS", "376", 100) IMP = add_currency("IMP", None, 100) INR = add_currency("INR", "356", 100) IQD = add_currency("IQD", "368", 1000) IRR = add_currency("IRR", "364", 100) ISK = add_currency("ISK", "352") JMD = add_currency("JMD", "388", 100) JOD = add_currency("JOD", "400", 1000) JPY = add_currency("JPY", "392") KES = add_currency("KES", "404", 100) KGS = add_currency("KGS", "417", 100) KHR = add_currency("KHR", "116", 100) KMF = add_currency("KMF", "174") KPW = add_currency("KPW", "408", 100) KRW = add_currency("KRW", "410") KWD = add_currency("KWD", "414", 1000) KYD = add_currency("KYD", "136", 100) KZT = add_currency("KZT", "398", 100) LAK = add_currency("LAK", "418", 100) LBP = add_currency("LBP", "422", 100) LKR = add_currency("LKR", "144", 100) LRD = add_currency("LRD", "430", 100) LSL = add_currency("LSL", "426", 100) LYD = add_currency("LYD", "434", 1000) MAD = add_currency("MAD", "504", 100) MDL = add_currency("MDL", "498", 100) MGA = add_currency("MGA", "969", 100) MKD = add_currency("MKD", "807", 100) MMK = add_currency("MMK", "104", 100) MNT = add_currency("MNT", "496", 100) MOP = add_currency("MOP", "446", 100) MUR = add_currency("MUR", "480", 100) MVR = add_currency("MVR", "462", 100) MWK = add_currency("MWK", "454", 100) MXN = add_currency("MXN", "484", 100) MXV = add_currency("MXV", "979", 100) MYR = add_currency("MYR", "458", 100) MZN = add_currency("MZN", "943", 100) NAD = add_currency("NAD", "516", 100) NGN = add_currency("NGN", "566", 100) NIO = add_currency("NIO", "558", 100) NOK = add_currency("NOK", "578", 100) NPR = add_currency("NPR", "524", 100) NZD = add_currency("NZD", "554", 100) OMR = add_currency("OMR", "512", 1000) PAB = add_currency("PAB", "590", 100) PEN = add_currency("PEN", "604", 100) PGK = add_currency("PGK", "598", 100) PHP = add_currency("PHP", "608", 100) PKR = add_currency("PKR", "586", 100) PLN = add_currency("PLN", "985", 100) PYG = add_currency("PYG", "600") QAR = add_currency("QAR", "634", 100) RON = add_currency("RON", "946", 100) RSD = add_currency("RSD", "941", 100) RUB = add_currency("RUB", "643", 100) RWF = add_currency("RWF", "646") SAR = add_currency("SAR", "682", 100) SBD = add_currency("SBD", "090", 100) SCR = add_currency("SCR", "690", 100) SDG = add_currency("SDG", "938", 100) SEK = add_currency("SEK", "752", 100) SGD = add_currency("SGD", "702", 100) SHP = add_currency("SHP", "654", 100) SLL = add_currency("SLL", "694", 100) SOS = add_currency("SOS", "706", 100) SRD = add_currency("SRD", "968", 100) SSP = add_currency("SSP", "728", 100) SVC = add_currency("SVC", "222", 100) SYP = add_currency("SYP", "760", 100) SZL = add_currency("SZL", "748", 100) THB = add_currency("THB", "764", 100) TJS = add_currency("TJS", "972", 100) TMT = add_currency("TMT", "934", 100) TND = add_currency("TND", "788", 1000) TOP = add_currency("TOP", "776", 100) TRY = add_currency("TRY", "949", 100) TTD = add_currency("TTD", "780", 100) TVD = add_currency("TVD", None, 100) TWD = add_currency("TWD", "901", 100) TZS = add_currency("TZS", "834", 100) UAH = add_currency("UAH", "980", 100) UGX = add_currency("UGX", "800") USD = add_currency("USD", "840", 100) USN = add_currency("USN", "997", 100) UYI = add_currency("UYI", "940") UYU = add_currency("UYU", "858", 100) UZS = add_currency("UZS", "860", 100) VND = add_currency("VND", "704") VUV = add_currency("VUV", "548") WST = add_currency("WST", "882", 100) XAF = add_currency("XAF", "950") XAG = add_currency("XAG", "961") XAU = add_currency("XAU", "959") XBA = add_currency("XBA", "955") XBB = add_currency("XBB", "956") XBC = add_currency("XBC", "957") XBD = add_currency("XBD", "958") XCD = add_currency("XCD", "951", 100) XDR = add_currency("XDR", "960") XFO = add_currency("XFO", None) XFU = add_currency("XFU", None) XOF = add_currency("XOF", "952") XPD = add_currency("XPD", "964") XPF = add_currency("XPF", "953") XPT = add_currency("XPT", "962") XSU = add_currency("XSU", "994") XTS = add_currency("XTS", "963") XUA = add_currency("XUA", "965") XXX = add_currency( "XXX", "999", # For backwards compat we keep values here, instead of getting # Babel's data. name="The codes assigned for transactions where no currency is involved", countries=["ZZ07_No_Currency"], ) YER = add_currency("YER", "886", 100) ZAR = add_currency("ZAR", "710", 100) ZMW = add_currency("ZMW", "967", 100) ZWN = add_currency("ZWN", "942", 100) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/src/moneyed/l10n.py0000644000175100001710000000141500000000000016355 0ustar00runnerdockerfrom typing import TYPE_CHECKING, Optional from babel.numbers import LC_NUMERIC from babel.numbers import format_currency as babel_format_currency if TYPE_CHECKING: from . import Money def format_money( money: "Money", format: Optional[str] = None, locale: str = LC_NUMERIC, currency_digits: bool = True, format_type: str = "standard", decimal_quantization: bool = True, ) -> str: """ See https://babel.pocoo.org/en/latest/api/numbers.html """ return babel_format_currency( # type: ignore[no-any-return] money.amount, money.currency.code, format=format, locale=locale, currency_digits=currency_digits, format_type=format_type, decimal_quantization=decimal_quantization, ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/src/moneyed/py.typed0000644000175100001710000000000000000000000016715 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038843.0 py-moneyed-2.0/src/moneyed/utils.py0000644000175100001710000000102300000000000016736 0ustar00runnerdockerfrom typing import Callable, Generic, TypeVar A = TypeVar("A") R = TypeVar("R") class cached_property(Generic[A, R]): """ Decorator that creates converts a method with a single self argument into a property cached on the instance. """ def __init__(self, func: Callable[[A], R]) -> None: self.func = func self.__doc__ = getattr(func, "__doc__") def __get__(self, instance: A, type: type) -> R: res = instance.__dict__[self.func.__name__] = self.func(instance) return res ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1622038872.4533162 py-moneyed-2.0/src/py_moneyed.egg-info/0000755000175100001710000000000000000000000017432 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038872.0 py-moneyed-2.0/src/py_moneyed.egg-info/PKG-INFO0000644000175100001710000000544000000000000020532 0ustar00runnerdockerMetadata-Version: 2.1 Name: py-moneyed Version: 2.0 Summary: Provides Currency and Money classes for use in your Python code. Home-page: UNKNOWN Author: Kai Author-email: k@limist.com Maintainer: Dmitry Dygalo Maintainer-email: dadygalo@gmail.com License: BSD Project-URL: Homepage, http://github.com/py-moneyed/py-moneyed Project-URL: Documentation, https://py-moneyed.readthedocs.io/en/latest/ Keywords: money currency class abstraction Platform: any Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Development Status :: 6 - Mature Classifier: Environment :: Other Environment Classifier: Intended Audience :: Developers Classifier: Topic :: Office/Business :: Financial Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.6 Description-Content-Type: text/x-rst Provides-Extra: tests Provides-Extra: type-tests License-File: LICENSE .. image:: https://github.com/py-moneyed/py-moneyed/workflows/build/badge.svg :target: https://github.com/py-moneyed/py-moneyed/actions?query=workflow%3Abuild :alt: Build Status .. image:: https://badge.fury.io/py/py-moneyed.svg :target: https://pypi.org/project/py-moneyed/ :alt: Latest PyPI version .. image:: https://readthedocs.org/projects/py-moneyed/badge/?version=latest :target: http://py-moneyed.readthedocs.io/en/latest/?badge=latest Overview ======== The need to represent instances of money frequently arises in software development, particularly any financial/economics software. To address that need, the py-moneyed package provides the classes of Money and Currency, at a level more useful than just using Python's Decimal class, or ($DEITY forbid) the float primitive. The package is meant to be stand-alone and used directly, or be subclassed further. py-moneyed is BSD-licensed. Quick start ----------- To install:: pip install py-moneyed Use: .. sourcecode:: python from moneyed import Money, USD five_dollars = Money(5, USD) You then use ``Money`` objects as if they were numbers, and they behave sensibly. See `docs `_ for more information (or the ``docs/`` folder). History ------- Some of the py-moneyed code was first derived from python-money available via this URL: http://code.google.com/p/python-money/ Due to inactivity, it was forked by @limist in 2010 and later moved to the py-moneyed organization. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038872.0 py-moneyed-2.0/src/py_moneyed.egg-info/SOURCES.txt0000644000175100001710000000111100000000000021310 0ustar00runnerdockerCHANGES.rst CONTRIBUTING.rst CONTRIBUTORS LICENSE MANIFEST.in README.rst RELEASE.rst pyproject.toml setup.cfg setup.py docs/Makefile docs/conf.py docs/conftest.py docs/contributing.rst docs/formatting.rst docs/history.rst docs/index.rst docs/installation.rst docs/make.bat docs/usage.rst src/moneyed/__init__.py src/moneyed/classes.py src/moneyed/l10n.py src/moneyed/py.typed src/moneyed/utils.py src/py_moneyed.egg-info/PKG-INFO src/py_moneyed.egg-info/SOURCES.txt src/py_moneyed.egg-info/dependency_links.txt src/py_moneyed.egg-info/requires.txt src/py_moneyed.egg-info/top_level.txt././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038872.0 py-moneyed-2.0/src/py_moneyed.egg-info/dependency_links.txt0000644000175100001710000000000100000000000023500 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038872.0 py-moneyed-2.0/src/py_moneyed.egg-info/requires.txt0000644000175100001710000000020600000000000022030 0ustar00runnerdockerbabel>=2.8.0 typing-extensions>=3.7.4.3 [tests] pytest>=2.3.0 tox>=1.6.0 [type-tests] pytest>=2.3.0 pytest-mypy-plugins mypy>=0.812 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1622038872.0 py-moneyed-2.0/src/py_moneyed.egg-info/top_level.txt0000644000175100001710000000001000000000000022153 0ustar00runnerdockermoneyed