stockholm


Namestockholm JSON
Version 0.5.7 PyPI version JSON
download
home_pagehttps://github.com/kalaspuff/stockholm
SummaryHuman friendly and flexible package for working with monetary amounts
upload_time2023-11-23 22:48:07
maintainer
docs_urlNone
authorCarl Oscar Aaro
requires_python>=3.8,<4.0
licenseMIT
keywords money monetary amount monetary value currency formatting protobuf protocol buffers graphql money graphql protobuf money protocol buffers money json python money monetary object python money class finance fintech
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # `stockholm`

**This brings a fully featured `Money` class for Python 3 – `stockholm.Money`.**

[![Python package](https://github.com/kalaspuff/stockholm/workflows/Python%20package/badge.svg)](https://github.com/kalaspuff/stockholm/actions/workflows/pythonpackage.yml)
[![pypi](https://badge.fury.io/py/stockholm.svg)](https://pypi.python.org/pypi/stockholm/)
[![Made with Python](https://img.shields.io/pypi/pyversions/stockholm)](https://www.python.org/)
[![MIT License](https://img.shields.io/github/license/kalaspuff/stockholm.svg)](https://github.com/kalaspuff/stockholm/blob/master/LICENSE)
[![Code coverage](https://codecov.io/gh/kalaspuff/stockholm/branch/master/graph/badge.svg)](https://codecov.io/gh/kalaspuff/stockholm/tree/master/stockholm)

*Library for formatting and performing arithmetic and comparison operations on monetary amounts. Also with support for currency handling, rates, exchange and serialization + deserialization for when transporting monetary amount data across network layers (built-in data generation and parsing).* πŸ’°

### A library for monetary amounts

* Combining an amount with a currency to create a monetary amount, as they usually should be read, written and transported together.
* Able to work with a plethora of different source types. Human friendly approach with developer experience in mind.
* Get rid of the gotchas if otherwise using `decimal.Decimal`. Sensible rounding by default. Never lose precision when making arithmetic operations. String output as you would expect.
* Generate (and parse) structured data to be used in transport layers such as GraphQL or Protobuf.
* Type hinted, battle tested and supporting several versions of Python.

#### Full feature set further down, but in its simplest form πŸ‘‡

```pycon
>>> Money("9001.42", currency="USD")
<stockholm.Money: "9001.42 USD">
```

![stockholm.Money](https://user-images.githubusercontent.com/89139/123852607-c9a0c380-d91c-11eb-9d47-cf7cd5751c01.png)

### Basic examples

Basically `stockholm` is a human friendly and modern `Money` class for Python 3. This is a library to be used by backend and frontend API coders of fintech companies, web merchants or subscription services. It's great for calculations of amounts while keeping a great level of precision.

```python
from stockholm import Money, Rate

loan_amount = Money("250380.00", currency="EUR")
# <stockholm.Money: "250380.00 EUR">

interest_rate = Rate(0.073)
# <stockholm.Rate: "0.073">

interest_per_day = loan_amount * (interest_rate / 365)
# <stockholm.Money: "50.076 EUR">
```

Comes with functions to produce output for transport layers as well as having a robust and easy way to import/export values in *GraphQL*, *JSON*, *Protocol Buffers*, etc.

```python
interest_per_day.asdict()
# {'value': '50.076 EUR', 'units': 50, 'nanos': 76000000, 'currency_code': 'EUR'}
```

```python
interest_per_day.asdict(keys=("amount", "currency"))
# {'amount': '50.076', 'currency': 'EUR'}
```

```python
interest_per_day.as_protobuf()
# <class 'google.type.money_pb2.Money'>
# Β· currency_code: "EUR"
# Β· units: 50
# Β· nanos: 76000000
```

The goal is to provide a flexible and robust package for development with any kind of monetary amounts. No more working with floats or having to deal with having to think about values in subunits for data transport layers or losing hours of sleep because of the default way that `Decimal` does rounding.

The monetary amounts can be transformed from (or into) dicts, strings, protobuf messages, json, floats, ints, Python Decimals, even other monetary amounts.

```python
from stockholm import Money, Number

gross_price = Money("319.20 SEK")
# <stockholm.Money: "319.20 SEK">

vat_rate = Number(0.25)  # 25% vat
vat_price = gross_price * vat_rate
# <stockholm.Money: "79.80 SEK">

net_price = gross_price + vat_price
# <stockholm.Money: "399.00 SEK">

total_sum = net_price * 5  # price of five items
# <stockholm.Money: "1995.00 SEK">

total_sum / 4  # total split on four people
# <stockholm.Money: "498.75 SEK">
```

Coding applications, libaries and microservices that consume and publish events that contain monetary amounts shouldn't be any harder than anything else. This package aims to ease that work. You can also use it for just numerical values of course.

#### Real life use-cases

There are times when you want to receive or publish events with monetary amounts or you need to expose an API endpoint and have a structured way to respond with balances, prices, vat, etc. without risking additional weirdness.

If you're developing a merchant solution, a ticketing service or webshop it can be great to have easy and structured interfaces for calculating orders and building summaries or reports.

#### We don't want to use `float`, but you can do more than just rely on `int` πŸ€”

Some may be interfacing with banking infrastructure from the 70s or 80s πŸ˜“ and has to process data in insanly old string based formats like the example below and validate sums, currencies, etc.

<p align="center">
<img width="580" alt="stockholm-parse-monetary-amounts" src="https://user-images.githubusercontent.com/89139/123870276-6588fa00-d932-11eb-9438-a4c58a44625b.png">
</p>

If any of these sounds familiar, a library for handling monetary amounts could help to structure interfaces you build – specially if you're on microservice architectures where code bases quickly gets a life of their own and teams will likely have different takes on their APIs unless strict guidelines (or utility libraries) are in place.

## The basic interfaces

### `from stockholm import Money`

The `stockholm.Money` object has full arithmetic support together with `int`, `float`, `Decimal`, other `Money` objects as well as `string`. The `stockholm.Money` object also supports complex string formatting functionality for easy debugging and a clean coding pattern.

```python
from stockholm import Money

Money("99.95 USD")
# <stockholm.Money: "99.95 USD">
```

### `from stockholm import Currency`

Currencies to monetary amounts can be specified using either currencies built with the `stockholm.Currency` metaclasses or simply by specifying the currency ticker as a string (for example `"SEK"` or `"EUR"`) when creating a new `Money` object.

Most currencies use two decimals in their default output. Some (like *JPY*) use fractions per default, and a few ones even has more than two decimals.

```python
from stockholm import Currency, Money

Money(1000, "CNY")
# <stockholm.Money: "1000.00 CNY">

Money(1000, Currency.USD)
# <stockholm.Money: "1000.00 USD">

Money(1000, Currency.JPY)
# <stockholm.Money: "1000 JPY">
```

Currencies using the `stockholm.Currency` metaclasses can hold additional options, such as default number of decimals in string output. Note that the amounts behind the scenes actually uses the same precision and backend as `Decimal` values and can as well be interchangable with such values, as such they are way more exact to do calculations with than floating point values.

### `from stockholm import Number, Rate`

The `Number` and `Rate` classes works in the same way and is similar to the `Money` class, with the exception that they cannot hold a currency type and cannot operate with sub units. Examples of when to use them could be to differentiate some values from monetary values, while still getting the benefits from the `Money` class.

Arithmetic operations between numbers and monetary `Money` values will usually result in a returned `Money` object. When instantiating a `Money` object the currency value can be overriden from the source amount, which could be useful when exchanging currencies.

```python
from stockholm import Money, Rate

jpy_money = Money(1352953, "JPY")
exchange_rate = Rate("0.08861326")
sek_money = Money(jpy_money * exchange_rate, "SEK")

print(f"I have {jpy_money:,.0m} which equals around {sek_money:,.2m}")
print(f"The exchange rate is {exchange_rate} ({jpy_money:c} -> {sek_money:c})")
# I have 1,352,953 JPY which equals around 119,889.58 SEK
# The exchange rate is 0.08861326 (JPY -> SEK)
```

## Installation with `pip`
Like you would install any other Python package, use `pip`, `poetry`, `pipenv` or your favourite tool.

```
$ pip install stockholm
```

To install with Protocol Buffers support, specify the `protobuf` extras.

```
$ pip install stockholm[protobuf]
```

## Topics in more detail

* [**Arithmetics – works with loads of compatible types – completely currency aware.**](#arithmetics---fully-supported)
* [**Instantiating a monetary amount in many flexible ways.**](#input-data-types-in-flexible-variants)
* [**Use in Pydantic models.**](#use-in-pydantic-models)
* [**Using `stockholm.Money` monetary amount with Protocol Buffers.**](#using-protocol-buffers-for-transporting-monetary-amounts-over-the-network)
* [**Conversion between dicts, JSON and values for use in GraphQL or other JSON-based API:s:**](#conversion-for-other-transport-medium-for-example-protocol-buffers-or-json)
  - [**Using dict values for input and output / having GraphQL in mind.**](#monetary-amounts-can-also-be-exported-to-dict-as-well-as-created-with-dict-value-input-which-can-be-great-to-for-example-transport-a-monetary-value-in-json)
  - [**Parsing and loading JSON data.**](#reading-or-outputting-monetary-amounts-as-json)
* [**Parameters and functions of the `stockholm.Money` object.**](#parameters-of-the-money-object)

### Arithmetics - fully supported

*Full arithmetic support with different types, backed by `Decimal` for dealing with rounding errors, while also keeping the monetary amount fully currency aware.*

```python
from stockholm import Money

money = Money("4711.50", currency="SEK")
print(money)
# 4711.50 SEK

output = (money + 100) * 3 + Money(50)
print(output)
# 14484.50 SEK

print(output / 5)
# 2896.90 SEK

print(round(output / 3, 4))
# 4828.1667 SEK

print(round(output / 3, 1))
# 4828.20 SEK

# Note that you can only do arithmetics on two monetary amounts which shares the
# same currency, monetary amounts that doesn't hold a currency at all or an
# operation between a currency aware monetary object and a value that doesn't hold
# data about a currency.
# Look at the following examples of completely legit operations.

Money("100 SEK") + Money("50 SEK")
# <stockholm.Money: "150.00 SEK">

Money("100 EUR") * 20 + 5 - 3.5
# <stockholm.Money: "2001.50 EUR">

Money("100 USD") - Money("10")
# <stockholm.Money: "90.00 USD">

Money("100") - Money("50") + 20
# <stockholm.Money: "70.00">

Money("100") + Money(2, currency="GBP")
# <stockholm.Money: "102.00 GBP">

Money("100", currency="EUR") + Money("10 EUR") - 50 + "20.51 EUR"
# <stockholm.Money: "80.51 EUR">

# And here's operations that tries to use two amounts with different currencies.

Money("100", currency="SEK") + Money("10 EUR")
# ! This results in a stockholm.exceptions.CurrencyMismatchError exception

Money(1) + Money("55 EUR") + Money(10, currency="EUR").to_currency("USD")
# ! This results in a stockholm.exceptions.CurrencyMismatchError exception

# Also note that you cannot multiply two currency aware monetary amounts by each
# other, for example say "5 EUR" * "5 EUR", that in that case would've resulted
# in "25 EUR EUR". A monetary amount can only hold one instance of currency.

Money("5 EUR") * Money("5 EUR")
# ! This results in a stockholm.exceptions.InvalidOperandError exception

```

### Formatting and advanced string formatting

Use f-string formatting for more human readable output and `money.as_string()` function to output with additional (or less) zero-padded fraction digits.

```python
from stockholm import Money

amount = Money("13384711 USD")

human_readable_amount = f"{amount:,m}"
# '13,384,711.00 USD'

amount_without_unnecessary_decimals = amount.as_string(min_decimals=0)
# '13384711 USD'
```

*Advanced string formatting functionality.*

```python
from stockholm import Money, Rate

jpy_money = Money(1352953, "JPY")
exchange_rate = Rate("0.08861326")
sek_money = Money(jpy_money * exchange_rate, "SEK")

print(f"I have {jpy_money:,.0m} which equals around {sek_money:,.2m}")
print(f"The exchange rate is {exchange_rate} ({jpy_money:c} -> {sek_money:c})")
# I have 1,352,953 JPY which equals around 119,889.58 SEK
# The exchange rate is 0.08861326 (JPY -> SEK)

# Standard string format uses default min decimals up to 9 decimals
print(f"{sek_money}")  # 119889.57595678 SEK

# Format type "f" works the same way as formatting a float or Decimal
print(f"{jpy_money:.0f}")  # 1352953
print(f"{sek_money:.2f}")  # 119889.58
print(f"{sek_money:.1f}")  # 119889.6
print(f"{sek_money:.0f}")  # 119890

# Format type "m" works as "f" but includes the currency in string output
print(f"{sek_money:.2m}")  # 119889.57 SEK
print(f"{sek_money:.4m}")  # 119889.5760 SEK
print(f"{sek_money:+,.4m}")  # +119,889.5760 SEK

# An uppercase "M" puts the currency ticker in front of the amount
print(f"{sek_money:.4M}")  # SEK 119889.5760

# Format type "c" will just output the currency used in the monetary amount
print(f"{sek_money:c}")  # SEK
```

### Currency class

##### *Use `stockholm.Currency` types for proper defaults of minimum number of decimal digits to output in strings, etc. All ISO 4217 currency codes implemented, see https://github.com/kalaspuff/stockholm/blob/master/stockholm/currency.py for the full list.*

```python
from stockholm import Currency, Money, get_currency
from stockholm.currency import JPY, SEK, EUR, IQD, USDCoin, Bitcoin

# Most currencies has a minimum default digits set to 2 in strings
print(Money(4711, SEK))  # 4711.00 SEK
print(Money(4711, EUR))  # 4711.00 EUR

# The stockholm.currency.JPY has a minimum default digits set to 0
print(Money(4711, JPY))  # 4711 JPY

# Some currencies even has a minimum default of 3 or 4 digits
print(Money(4711, IQD))  # 4711.000 IQD

# Some complex non ISO 4217 currencies, assets or tokens may define
# their own ticker, for example a "USD Coin" uses the ticker "USDC"
print(Money(4711, USDCoin))  # 4711.00 USDC
print(Money(4711, Bitcoin))  # 4711.00 BTC

# You can also use the shorthand stockholm.Currency object which
# holds all ISO 4217 three character codes as objects.
print(Money(1338, Currency.JPY))  # 1338 JPY

# or call the get_currency function
print(Money(1338, get_currency("JPY")))  # 1338 JPY

```

### Parsing input

#### Input data types in flexible variants

*Flexible ways for assigning values to a monetary amount using many different input data types and methods.*

```python
from decimal import Decimal
from stockholm import Money

Money(100, currency="EUR")
# <stockholm.Money: "100.00 EUR">

Money("1338 USD")
# <stockholm.Money: "1338.00 USD">

Money("0.5")
# <stockholm.Money: "0.50">

amount = Decimal(5000) / 3
Money(amount, currency="XDR")
# <stockholm.Money: "1666.666666667 XDR">

money = Money("0.30285471")
Money(money, currency="BTC")
# <stockholm.Money: "0.30285471 BTC">

# Reading values as "sub units" (multiplied by 100) can come in handy when parsing
# some older types of banking files, where all values are presented as strings in
# cents / ΓΆren / etc.
cents_as_str = "471100"
money = Money(cents_as_str, currency="USD", from_sub_units=True)
# <stockholm.Money: "4711.00 USD">
money.sub_units
# Decimal('471100')
```

### List arithmetics - summary of monetary amounts in list

*Adding several monetary amounts from a list.*

```python
from stockholm import Money

amounts = [
    Money(1),
    Money("1.50"),
    Money("1000"),
]

# Use Money.sum to deal with complex values of different data types
Money.sum(amounts)
# <stockholm.Money: "1002.50">

# Built-in sum may also be used (if only working with monetary amounts)
sum(amounts)
# <stockholm.Money: "1002.50">
```

### Use in Pydantic models

`Money` objects can be used in Pydantic (`Pydantic>=2.2` supported) models and used with Pydantic's JSON serialization and validation – the same goes for `Number` and `Currency` objects as well. Specify the `stockholm.Money` type as the field type and you're good to go.

```python
from pydantic import BaseModel
from stockholm import Money

class Transaction(BaseModel):
    reference: str
    amount: Money

transaction = Transaction(reference="abc123", amount=Money("100.00", "SEK"))
# Transaction(reference='abc123', amount=<stockholm.Money: "100.00 SEK">)

json_data = transaction.model_dump_json()
# '{"reference":"abc123","amount":{"value":"100.00 SEK","units":100,"nanos":0,"currency_code":"SEK"}}'

Transaction.model_validate_json(json_data)
# Transaction(reference='abc123', amount=<stockholm.Money: "100.00 SEK">)
```

It's also possible to use the `stockholm.types` Pydantic field types, for example `stockholm.types.ConvertibleToMoney`, which will automatically coerce input into a `Money` object.

```python
from pydantic import BaseModel
from stockholm import Money
from stockholm.types import ConvertibleToMoney

class ExampleModel(BaseModel):
    amount: ConvertibleToMoney

example = ExampleModel(amount="4711.50 USD")
# ExampleModel(amount=<stockholm.Money: "4711.50 USD">)

example.model_dump_json()
# '{"amount":{"value":"4711.50 USD","units":4711,"nanos":500000000,"currency_code":"USD"}}'
```

Other similar field types that can be used on Pydantic fields are `ConvertibleToNumber`, `ConvertibleToMoneyWithRequiredCurrency` and `ConvertibleToCurrency` – all imported from `stockholm.types`.

Note that it's generally recommended to opt for the more strict types (`stockholm.Money`, `stockholm.Number` and `stockholm.Currency`) when possible and the coercion types should be used with caution and is mainly suited for experimentation and early development.

### Conversion for other transport medium (for example Protocol Buffers or JSON)

##### *Easily splittable into `units` and `nanos` for transport in network medium, for example using the [`google.type.Money` protobuf definition](https://github.com/googleapis/googleapis/blob/master/google/type/money.proto) when using Protocol Buffers.*

```python
from stockholm import Money

money = Money("22583.75382", "SEK")
money.units, money.nanos, money.currency_code
# (22583, 753820000, 'SEK')

# or vice versa
Money(units=22583, nanos=753820000, currency="SEK")
# <stockholm.Money: "22583.75382 SEK">
```

##### *Monetary amounts can also be exported to `dict` as well as created with `dict` value input, which can be great to for example transport a monetary value in JSON.*

```python
from stockholm import Money

money = Money("4711.75", "SEK")
dict(money)  # or by using: money.asdict()
# {'value': '4711.75 SEK', 'units': 4711, 'nanos': 750000000, 'currency_code': 'SEK'}

# A monetary amount object can be created from a dict either by passing dict directly
# to the Money() constructor or by using Money.from_dict(dict_input). Not all values
# needs to be available in the input dict, either "units", "nanos", "value" or "amount"
# should be specified or any combination of them, as long as values would result in the
# same output monetary value.
money = Money.from_dict({
    "value": "4711.75 SEK",
    "units": 4711,
    "nanos": 750000000,
    "currency_code": "SEK"
})
# <stockholm.Money: "4711.75 SEK">
```

The `money.asdict()` function can be called with an optional `keys` argument, which can be used to specify a tuple of keys which shuld be used in the returned dict.

The default behaviour of `money.asdict()` is equivalent to `money.asdict(keys=("value", "units", "nanos", "currency_code"))`.

Values to use in the `keys` tuple for `stockholm.Money` objects are any combination of the following:

| key | description | return type | example |
| :-- | :---------- | :---------- | -------: |
| `value` | amount + currency code | `str` | `"9001.50 USD"`
| `units` | units of the amount | `int` | `9001` |
| `nanos` | number of nano units of the amount | `int` | `500000000` |
| `currency_code` | currency code if available | `str \| None` | `"USD"` |
| `currency` | currency code if available | `str \| None` | `"USD"` |
| `amount` | the monetary amount (excl. currency code) | `str` | `"9001.50"` |

```python
from stockholm import Money

Money("4711 USD").asdict(keys=("value", "units", "nanos", "currency_code"))
# {'value': '4711.00 USD', 'units': 4711, 'nanos': 0, 'currency_code': 'USD'}

Money("4711 USD").asdict(keys=("amount", "currency"))
# {'amount': '4711.00', 'currency': 'USD'}

Money(nanos=10).asdict(keys=("value", "currency", "units", "nanos"))
# {'value': '0.00000001', 'currency': None, 'units': 0, 'nanos': 10}
```

##### *Using Protocol Buffers for transporting monetary amounts over the network.*

```python
from stockholm import Money

# By default we're utilizing Google's protobuf message called google.type.Money, however
# the protobuf class can be overriden with your own if using similar keys and value types.
# https://github.com/googleapis/googleapis/blob/master/google/type/money.proto

money = Money("4711.75", "SEK")
money.as_protobuf()
# This will produce a protobuf object which by default holds values for units, nanos and
# currency_code as per the google.type.Money protobuf message definition.
# Use money.as_protobuf(proto_class=YourProtoClass) if you're using custom messages that
# are not of Google's proto message type.
#
# To get the exact byte output produced from the proto class, call their
# SerailizeToString() function.
money.as_protobuf().SerializeToString()
# b'\n\x03SEK\x10\xe7$\x18\x80\xaf\xd0\xe5\x02'

# Of course we can also instantiate a monetary amount object by passing a proto message,
# either by using the already parsed proto object, or by passing the byte data directly.
# If no proto_class keyword argument is specified, we'll once again default to
# google.type.Money.
money = Money.from_protobuf(b'\n\x03SEK\x10\xe7$\x18\x80\xaf\xd0\xe5\x02')
# <stockholm.Money: "4711.75 SEK">

# In another example we'll build the message just before hand to be extra descriptive
# of what's happening. The stockholm.MoneyProtobufMessage (or stockholm.protobuf.Money)
# class is a generated Python representation of the google.type.Money protobuf message
# definition. You can also use your own custom class.
from stockholm import MoneyProtobufMessage
message = MoneyProtobufMessage()
message.units = 2549
message.nanos = 990000000
message.currency_code = "USD"
# If you're using custom classes that aren't generated from google.type.Money, then pass
# your generated class as the proto_class keyword argument. In this example, it's not
# actually needed, since MoneyProtobufMessage is built from google.type.Money definitions.
money = Money.from_protobuf(message, proto_class=MoneyProtobufMessage)
# <stockholm.Money: "2549.99 USD">
message.SerializeToString()
# b'\x10\xf5\x13\x18\x80\xe7\x88\xd8\x03'

# Usually the byte data may already be parsed from your proto class into your
# proto objects, and if you're using google.type.Money in your messages you could
# pass in the object without any additional proto_class keyword.
#
# In the following example we have a message that contains a field on position 1
# named "remaining_sum", which in turn holds a google.type.Money value.
#
# Let's say the message holds the following as a parsed proto object:
# remaining_sum {
#  currency_code: "USD"
#  units: 42
# }
#
# It's binary representation is b'\n\x07\n\x03USD\x10*'.
# And the binary representation of message.remaining_sum is b'\n\x03USD\x10*'.
#
# By passing the monetary part of the message (in this case, the field remaining_sum)
# we can immediately create a monetary amount object which is currency aware.
money = Money.from_protobuf(message.remaining_sum)
# <stockholm.Money: "42.00 USD">
#
# Of course this newly instantiated montary amount object can be accessed in many
# different ways, can use arithmetics like normally, etc.
money.amount
# Decimal('42.000000000')
money.units
# 42
money.nanos
# 0
money.currency
# "USD"
money + 10
# <stockholm.Money: "52.00 USD">
money * 31 - 20 + Money("0.50")
# <stockholm.Money: "1282.50 USD">
```

##### *Reading or outputting monetary amounts as JSON*

```python
from stockholm import Money

# Outputting key-values as a dict or JSON string. For example great when sending monetary
# amounts over GraphQL or internal API:s.
money = Money(5767.50, currency="EUR")
# <stockholm.Money: "5767.50 EUR">
#
# If no keys keyword argument is specified the default keys will be used, which is
# value, units, nanos and currency_code.
money.as_json()
# '{"value": "5767.50 EUR", "units": 5767, "nanos": 500000000, "currency_code": "EUR"}'
#
# Besides value, units, nanos and currency_code, the other keys that can be specified
# are amount and currency (converted to str and equivalent to currency_code in this
# context).
money.as_json(keys=("amount", "currency_code"))
# '{"amount": "5767.500000000", "currency_code": "EUR"}'

# It's also possible directly parse a monetary amount from its incoming JSON string
Money.from_json('{"value": "5767.50 EUR", "units": 5767, "nanos": 500000000}')
# <stockholm.Money: "5767.50 EUR">
Money.from_json('{"amount": "5767.500000000", "currency_code": "EUR"}')
# <stockholm.Money: "5767.50 EUR">
```

#### Parameters of the Money object

```python
from stockholm import Currency, Money

# This is our monetary object, instantiated as 59112.50 EUR using the
# currency object stockholm.Currency.EUR, which among other things holds data
# regarding how many decimal digits should normally be printed. A monetary amount
# in EUR is usually demoninated with two decimal digits.

money = Money("59112.50", currency=Currency.EUR)
# <stockholm.Money: "59112.50 EUR">

money.amount
# Decimal('59112.50')
# Type: decimal.Decimal

money.value
# '59112.50 EUR'
# Type: string

money.units
# 59112
# Type: integer

money.nanos
# 500000000
# Type: integer

money.currency_code
# 'EUR'
# Type: Either: A string or None

money.currency
# <stockholm.Currency: "EUR">
# Type: Either: a currency object, a string (equivalent to currency_code) or None

money.sub_units
# Decimal('5911250')
# Type: decimal.Decimal

money.asdict()
# {'value': '59112.50 EUR', 'units': 59112, 'nanos': 500000000, 'currency_code': 'EUR'}
# Type: dict

money.as_string()  # or: str(money)
# '59112.50 EUR'
# Type: string

money.as_int()  # or: int(money)
# 59112
# Type: integer

money.as_float()  # or: float(money)
# 59112.5
# Type: float
# Note that using floats may cause you to lose precision. Floats are strongly discouraged.

money.is_signed()
# False
# Type: boolean

money.is_zero()
# False
# Type: boolean

money.to_integral()
# <stockholm.Money: "59113.00 EUR">
# Type: stockholm.Money

money.amount_as_string(min_decimals=4, max_decimals=7)
# 59112.5000
# Type: string

money.amount_as_string(min_decimals=0)
# 59112.5
# Type: string

money.amount_as_string(max_decimals=0)
# 59113
# Type: string

money.to_currency(currency="SEK")
# <stockholm.Money: "59113.50 SEK">
# Type: stockholm.Money

money.as_json()
# '{"value": "59112.50 EUR", "units": 59112, "nanos": 500000000, "currency_code": "EUR"}'
# Type: string

money.as_json(keys=("amount", "currency"))
# '{"amount": "59112.50", "currency": "EUR"}'
# Type: string

money.as_protobuf()
# currency_code: "EUR"
# units: 59112
# nanos: 500000000
# Type: stockholm.protobuf.money_pb2.Money, generated from proto definitions at
# https://github.com/googleapis/googleapis/blob/master/google/type/money.proto

money.as_protobuf(proto_class=CustomMoneyProtobufMessage)
# Type: An instance of CustomMoneyProtobufMessage populated with the properties of money
```

*A simple, yet powerful way of coding with money.*

## Acknowledgements

Built with inspiration from https://github.com/carlospalol/money and https://github.com/vimeo/py-money


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/kalaspuff/stockholm",
    "name": "stockholm",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.8,<4.0",
    "maintainer_email": "",
    "keywords": "money,monetary amount,monetary value,currency,formatting,protobuf,protocol buffers,graphql,money graphql,protobuf money,protocol buffers money,json,python money,monetary object,python money class,finance,fintech",
    "author": "Carl Oscar Aaro",
    "author_email": "hello@carloscar.com",
    "download_url": "https://files.pythonhosted.org/packages/2b/0c/2bf69ec49a1303512d65c4ea953facd0e0486d94603cabaee85be824738d/stockholm-0.5.7.tar.gz",
    "platform": null,
    "description": "# `stockholm`\n\n**This brings a fully featured `Money` class for Python 3 \u2013 `stockholm.Money`.**\n\n[![Python package](https://github.com/kalaspuff/stockholm/workflows/Python%20package/badge.svg)](https://github.com/kalaspuff/stockholm/actions/workflows/pythonpackage.yml)\n[![pypi](https://badge.fury.io/py/stockholm.svg)](https://pypi.python.org/pypi/stockholm/)\n[![Made with Python](https://img.shields.io/pypi/pyversions/stockholm)](https://www.python.org/)\n[![MIT License](https://img.shields.io/github/license/kalaspuff/stockholm.svg)](https://github.com/kalaspuff/stockholm/blob/master/LICENSE)\n[![Code coverage](https://codecov.io/gh/kalaspuff/stockholm/branch/master/graph/badge.svg)](https://codecov.io/gh/kalaspuff/stockholm/tree/master/stockholm)\n\n*Library for formatting and performing arithmetic and comparison operations on monetary amounts. Also with support for currency handling, rates, exchange and serialization + deserialization for when transporting monetary amount data across network layers (built-in data generation and parsing).* \ud83d\udcb0\n\n### A library for monetary amounts\n\n* Combining an amount with a currency to create a monetary amount, as they usually should be read, written and transported together.\n* Able to work with a plethora of different source types. Human friendly approach with developer experience in mind.\n* Get rid of the gotchas if otherwise using `decimal.Decimal`. Sensible rounding by default. Never lose precision when making arithmetic operations. String output as you would expect.\n* Generate (and parse) structured data to be used in transport layers such as GraphQL or Protobuf.\n* Type hinted, battle tested and supporting several versions of Python.\n\n#### Full feature set further down, but in its simplest form \ud83d\udc47\n\n```pycon\n>>> Money(\"9001.42\", currency=\"USD\")\n<stockholm.Money: \"9001.42 USD\">\n```\n\n![stockholm.Money](https://user-images.githubusercontent.com/89139/123852607-c9a0c380-d91c-11eb-9d47-cf7cd5751c01.png)\n\n### Basic examples\n\nBasically `stockholm` is a human friendly and modern `Money` class for Python 3. This is a library to be used by backend and frontend API coders of fintech companies, web merchants or subscription services. It's great for calculations of amounts while keeping a great level of precision.\n\n```python\nfrom stockholm import Money, Rate\n\nloan_amount = Money(\"250380.00\", currency=\"EUR\")\n# <stockholm.Money: \"250380.00 EUR\">\n\ninterest_rate = Rate(0.073)\n# <stockholm.Rate: \"0.073\">\n\ninterest_per_day = loan_amount * (interest_rate / 365)\n# <stockholm.Money: \"50.076 EUR\">\n```\n\nComes with functions to produce output for transport layers as well as having a robust and easy way to import/export values in *GraphQL*, *JSON*, *Protocol Buffers*, etc.\n\n```python\ninterest_per_day.asdict()\n# {'value': '50.076 EUR', 'units': 50, 'nanos': 76000000, 'currency_code': 'EUR'}\n```\n\n```python\ninterest_per_day.asdict(keys=(\"amount\", \"currency\"))\n# {'amount': '50.076', 'currency': 'EUR'}\n```\n\n```python\ninterest_per_day.as_protobuf()\n# <class 'google.type.money_pb2.Money'>\n# \u00b7 currency_code: \"EUR\"\n# \u00b7 units: 50\n# \u00b7 nanos: 76000000\n```\n\nThe goal is to provide a flexible and robust package for development with any kind of monetary amounts. No more working with floats or having to deal with having to think about values in subunits for data transport layers or losing hours of sleep because of the default way that `Decimal` does rounding.\n\nThe monetary amounts can be transformed from (or into) dicts, strings, protobuf messages, json, floats, ints, Python Decimals, even other monetary amounts.\n\n```python\nfrom stockholm import Money, Number\n\ngross_price = Money(\"319.20 SEK\")\n# <stockholm.Money: \"319.20 SEK\">\n\nvat_rate = Number(0.25)  # 25% vat\nvat_price = gross_price * vat_rate\n# <stockholm.Money: \"79.80 SEK\">\n\nnet_price = gross_price + vat_price\n# <stockholm.Money: \"399.00 SEK\">\n\ntotal_sum = net_price * 5  # price of five items\n# <stockholm.Money: \"1995.00 SEK\">\n\ntotal_sum / 4  # total split on four people\n# <stockholm.Money: \"498.75 SEK\">\n```\n\nCoding applications, libaries and microservices that consume and publish events that contain monetary amounts shouldn't be any harder than anything else. This package aims to ease that work. You can also use it for just numerical values of course.\n\n#### Real life use-cases\n\nThere are times when you want to receive or publish events with monetary amounts or you need to expose an API endpoint and have a structured way to respond with balances, prices, vat, etc. without risking additional weirdness.\n\nIf you're developing a merchant solution, a ticketing service or webshop it can be great to have easy and structured interfaces for calculating orders and building summaries or reports.\n\n#### We don't want to use `float`, but you can do more than just rely on `int` \ud83e\udd14\n\nSome may be interfacing with banking infrastructure from the 70s or 80s \ud83d\ude13 and has to process data in insanly old string based formats like the example below and validate sums, currencies, etc.\n\n<p align=\"center\">\n<img width=\"580\" alt=\"stockholm-parse-monetary-amounts\" src=\"https://user-images.githubusercontent.com/89139/123870276-6588fa00-d932-11eb-9438-a4c58a44625b.png\">\n</p>\n\nIf any of these sounds familiar, a library for handling monetary amounts could help to structure interfaces you build \u2013 specially if you're on microservice architectures where code bases quickly gets a life of their own and teams will likely have different takes on their APIs unless strict guidelines (or utility libraries) are in place.\n\n## The basic interfaces\n\n### `from stockholm import Money`\n\nThe `stockholm.Money` object has full arithmetic support together with `int`, `float`, `Decimal`, other `Money` objects as well as `string`. The `stockholm.Money` object also supports complex string formatting functionality for easy debugging and a clean coding pattern.\n\n```python\nfrom stockholm import Money\n\nMoney(\"99.95 USD\")\n# <stockholm.Money: \"99.95 USD\">\n```\n\n### `from stockholm import Currency`\n\nCurrencies to monetary amounts can be specified using either currencies built with the `stockholm.Currency` metaclasses or simply by specifying the currency ticker as a string (for example `\"SEK\"` or `\"EUR\"`) when creating a new `Money` object.\n\nMost currencies use two decimals in their default output. Some (like *JPY*) use fractions per default, and a few ones even has more than two decimals.\n\n```python\nfrom stockholm import Currency, Money\n\nMoney(1000, \"CNY\")\n# <stockholm.Money: \"1000.00 CNY\">\n\nMoney(1000, Currency.USD)\n# <stockholm.Money: \"1000.00 USD\">\n\nMoney(1000, Currency.JPY)\n# <stockholm.Money: \"1000 JPY\">\n```\n\nCurrencies using the `stockholm.Currency` metaclasses can hold additional options, such as default number of decimals in string output. Note that the amounts behind the scenes actually uses the same precision and backend as `Decimal` values and can as well be interchangable with such values, as such they are way more exact to do calculations with than floating point values.\n\n### `from stockholm import Number, Rate`\n\nThe `Number` and `Rate` classes works in the same way and is similar to the `Money` class, with the exception that they cannot hold a currency type and cannot operate with sub units. Examples of when to use them could be to differentiate some values from monetary values, while still getting the benefits from the `Money` class.\n\nArithmetic operations between numbers and monetary `Money` values will usually result in a returned `Money` object. When instantiating a `Money` object the currency value can be overriden from the source amount, which could be useful when exchanging currencies.\n\n```python\nfrom stockholm import Money, Rate\n\njpy_money = Money(1352953, \"JPY\")\nexchange_rate = Rate(\"0.08861326\")\nsek_money = Money(jpy_money * exchange_rate, \"SEK\")\n\nprint(f\"I have {jpy_money:,.0m} which equals around {sek_money:,.2m}\")\nprint(f\"The exchange rate is {exchange_rate} ({jpy_money:c} -> {sek_money:c})\")\n# I have 1,352,953 JPY which equals around 119,889.58 SEK\n# The exchange rate is 0.08861326 (JPY -> SEK)\n```\n\n## Installation with `pip`\nLike you would install any other Python package, use `pip`, `poetry`, `pipenv` or your favourite tool.\n\n```\n$ pip install stockholm\n```\n\nTo install with Protocol Buffers support, specify the `protobuf` extras.\n\n```\n$ pip install stockholm[protobuf]\n```\n\n## Topics in more detail\n\n* [**Arithmetics \u2013 works with loads of compatible types \u2013 completely currency aware.**](#arithmetics---fully-supported)\n* [**Instantiating a monetary amount in many flexible ways.**](#input-data-types-in-flexible-variants)\n* [**Use in Pydantic models.**](#use-in-pydantic-models)\n* [**Using `stockholm.Money` monetary amount with Protocol Buffers.**](#using-protocol-buffers-for-transporting-monetary-amounts-over-the-network)\n* [**Conversion between dicts, JSON and values for use in GraphQL or other JSON-based API:s:**](#conversion-for-other-transport-medium-for-example-protocol-buffers-or-json)\n  - [**Using dict values for input and output / having GraphQL in mind.**](#monetary-amounts-can-also-be-exported-to-dict-as-well-as-created-with-dict-value-input-which-can-be-great-to-for-example-transport-a-monetary-value-in-json)\n  - [**Parsing and loading JSON data.**](#reading-or-outputting-monetary-amounts-as-json)\n* [**Parameters and functions of the `stockholm.Money` object.**](#parameters-of-the-money-object)\n\n### Arithmetics - fully supported\n\n*Full arithmetic support with different types, backed by `Decimal` for dealing with rounding errors, while also keeping the monetary amount fully currency aware.*\n\n```python\nfrom stockholm import Money\n\nmoney = Money(\"4711.50\", currency=\"SEK\")\nprint(money)\n# 4711.50 SEK\n\noutput = (money + 100) * 3 + Money(50)\nprint(output)\n# 14484.50 SEK\n\nprint(output / 5)\n# 2896.90 SEK\n\nprint(round(output / 3, 4))\n# 4828.1667 SEK\n\nprint(round(output / 3, 1))\n# 4828.20 SEK\n\n# Note that you can only do arithmetics on two monetary amounts which shares the\n# same currency, monetary amounts that doesn't hold a currency at all or an\n# operation between a currency aware monetary object and a value that doesn't hold\n# data about a currency.\n# Look at the following examples of completely legit operations.\n\nMoney(\"100 SEK\") + Money(\"50 SEK\")\n# <stockholm.Money: \"150.00 SEK\">\n\nMoney(\"100 EUR\") * 20 + 5 - 3.5\n# <stockholm.Money: \"2001.50 EUR\">\n\nMoney(\"100 USD\") - Money(\"10\")\n# <stockholm.Money: \"90.00 USD\">\n\nMoney(\"100\") - Money(\"50\") + 20\n# <stockholm.Money: \"70.00\">\n\nMoney(\"100\") + Money(2, currency=\"GBP\")\n# <stockholm.Money: \"102.00 GBP\">\n\nMoney(\"100\", currency=\"EUR\") + Money(\"10 EUR\") - 50 + \"20.51 EUR\"\n# <stockholm.Money: \"80.51 EUR\">\n\n# And here's operations that tries to use two amounts with different currencies.\n\nMoney(\"100\", currency=\"SEK\") + Money(\"10 EUR\")\n# ! This results in a stockholm.exceptions.CurrencyMismatchError exception\n\nMoney(1) + Money(\"55 EUR\") + Money(10, currency=\"EUR\").to_currency(\"USD\")\n# ! This results in a stockholm.exceptions.CurrencyMismatchError exception\n\n# Also note that you cannot multiply two currency aware monetary amounts by each\n# other, for example say \"5 EUR\" * \"5 EUR\", that in that case would've resulted\n# in \"25 EUR EUR\". A monetary amount can only hold one instance of currency.\n\nMoney(\"5 EUR\") * Money(\"5 EUR\")\n# ! This results in a stockholm.exceptions.InvalidOperandError exception\n\n```\n\n### Formatting and advanced string formatting\n\nUse f-string formatting for more human readable output and `money.as_string()` function to output with additional (or less) zero-padded fraction digits.\n\n```python\nfrom stockholm import Money\n\namount = Money(\"13384711 USD\")\n\nhuman_readable_amount = f\"{amount:,m}\"\n# '13,384,711.00 USD'\n\namount_without_unnecessary_decimals = amount.as_string(min_decimals=0)\n# '13384711 USD'\n```\n\n*Advanced string formatting functionality.*\n\n```python\nfrom stockholm import Money, Rate\n\njpy_money = Money(1352953, \"JPY\")\nexchange_rate = Rate(\"0.08861326\")\nsek_money = Money(jpy_money * exchange_rate, \"SEK\")\n\nprint(f\"I have {jpy_money:,.0m} which equals around {sek_money:,.2m}\")\nprint(f\"The exchange rate is {exchange_rate} ({jpy_money:c} -> {sek_money:c})\")\n# I have 1,352,953 JPY which equals around 119,889.58 SEK\n# The exchange rate is 0.08861326 (JPY -> SEK)\n\n# Standard string format uses default min decimals up to 9 decimals\nprint(f\"{sek_money}\")  # 119889.57595678 SEK\n\n# Format type \"f\" works the same way as formatting a float or Decimal\nprint(f\"{jpy_money:.0f}\")  # 1352953\nprint(f\"{sek_money:.2f}\")  # 119889.58\nprint(f\"{sek_money:.1f}\")  # 119889.6\nprint(f\"{sek_money:.0f}\")  # 119890\n\n# Format type \"m\" works as \"f\" but includes the currency in string output\nprint(f\"{sek_money:.2m}\")  # 119889.57 SEK\nprint(f\"{sek_money:.4m}\")  # 119889.5760 SEK\nprint(f\"{sek_money:+,.4m}\")  # +119,889.5760 SEK\n\n# An uppercase \"M\" puts the currency ticker in front of the amount\nprint(f\"{sek_money:.4M}\")  # SEK 119889.5760\n\n# Format type \"c\" will just output the currency used in the monetary amount\nprint(f\"{sek_money:c}\")  # SEK\n```\n\n### Currency class\n\n##### *Use `stockholm.Currency` types for proper defaults of minimum number of decimal digits to output in strings, etc. All ISO 4217 currency codes implemented, see https://github.com/kalaspuff/stockholm/blob/master/stockholm/currency.py for the full list.*\n\n```python\nfrom stockholm import Currency, Money, get_currency\nfrom stockholm.currency import JPY, SEK, EUR, IQD, USDCoin, Bitcoin\n\n# Most currencies has a minimum default digits set to 2 in strings\nprint(Money(4711, SEK))  # 4711.00 SEK\nprint(Money(4711, EUR))  # 4711.00 EUR\n\n# The stockholm.currency.JPY has a minimum default digits set to 0\nprint(Money(4711, JPY))  # 4711 JPY\n\n# Some currencies even has a minimum default of 3 or 4 digits\nprint(Money(4711, IQD))  # 4711.000 IQD\n\n# Some complex non ISO 4217 currencies, assets or tokens may define\n# their own ticker, for example a \"USD Coin\" uses the ticker \"USDC\"\nprint(Money(4711, USDCoin))  # 4711.00 USDC\nprint(Money(4711, Bitcoin))  # 4711.00 BTC\n\n# You can also use the shorthand stockholm.Currency object which\n# holds all ISO 4217 three character codes as objects.\nprint(Money(1338, Currency.JPY))  # 1338 JPY\n\n# or call the get_currency function\nprint(Money(1338, get_currency(\"JPY\")))  # 1338 JPY\n\n```\n\n### Parsing input\n\n#### Input data types in flexible variants\n\n*Flexible ways for assigning values to a monetary amount using many different input data types and methods.*\n\n```python\nfrom decimal import Decimal\nfrom stockholm import Money\n\nMoney(100, currency=\"EUR\")\n# <stockholm.Money: \"100.00 EUR\">\n\nMoney(\"1338 USD\")\n# <stockholm.Money: \"1338.00 USD\">\n\nMoney(\"0.5\")\n# <stockholm.Money: \"0.50\">\n\namount = Decimal(5000) / 3\nMoney(amount, currency=\"XDR\")\n# <stockholm.Money: \"1666.666666667 XDR\">\n\nmoney = Money(\"0.30285471\")\nMoney(money, currency=\"BTC\")\n# <stockholm.Money: \"0.30285471 BTC\">\n\n# Reading values as \"sub units\" (multiplied by 100) can come in handy when parsing\n# some older types of banking files, where all values are presented as strings in\n# cents / \u00f6ren / etc.\ncents_as_str = \"471100\"\nmoney = Money(cents_as_str, currency=\"USD\", from_sub_units=True)\n# <stockholm.Money: \"4711.00 USD\">\nmoney.sub_units\n# Decimal('471100')\n```\n\n### List arithmetics - summary of monetary amounts in list\n\n*Adding several monetary amounts from a list.*\n\n```python\nfrom stockholm import Money\n\namounts = [\n    Money(1),\n    Money(\"1.50\"),\n    Money(\"1000\"),\n]\n\n# Use Money.sum to deal with complex values of different data types\nMoney.sum(amounts)\n# <stockholm.Money: \"1002.50\">\n\n# Built-in sum may also be used (if only working with monetary amounts)\nsum(amounts)\n# <stockholm.Money: \"1002.50\">\n```\n\n### Use in Pydantic models\n\n`Money` objects can be used in Pydantic (`Pydantic>=2.2` supported) models and used with Pydantic's JSON serialization and validation \u2013 the same goes for `Number` and `Currency` objects as well. Specify the `stockholm.Money` type as the field type and you're good to go.\n\n```python\nfrom pydantic import BaseModel\nfrom stockholm import Money\n\nclass Transaction(BaseModel):\n    reference: str\n    amount: Money\n\ntransaction = Transaction(reference=\"abc123\", amount=Money(\"100.00\", \"SEK\"))\n# Transaction(reference='abc123', amount=<stockholm.Money: \"100.00 SEK\">)\n\njson_data = transaction.model_dump_json()\n# '{\"reference\":\"abc123\",\"amount\":{\"value\":\"100.00 SEK\",\"units\":100,\"nanos\":0,\"currency_code\":\"SEK\"}}'\n\nTransaction.model_validate_json(json_data)\n# Transaction(reference='abc123', amount=<stockholm.Money: \"100.00 SEK\">)\n```\n\nIt's also possible to use the `stockholm.types` Pydantic field types, for example `stockholm.types.ConvertibleToMoney`, which will automatically coerce input into a `Money` object.\n\n```python\nfrom pydantic import BaseModel\nfrom stockholm import Money\nfrom stockholm.types import ConvertibleToMoney\n\nclass ExampleModel(BaseModel):\n    amount: ConvertibleToMoney\n\nexample = ExampleModel(amount=\"4711.50 USD\")\n# ExampleModel(amount=<stockholm.Money: \"4711.50 USD\">)\n\nexample.model_dump_json()\n# '{\"amount\":{\"value\":\"4711.50 USD\",\"units\":4711,\"nanos\":500000000,\"currency_code\":\"USD\"}}'\n```\n\nOther similar field types that can be used on Pydantic fields are `ConvertibleToNumber`, `ConvertibleToMoneyWithRequiredCurrency` and `ConvertibleToCurrency` \u2013 all imported from `stockholm.types`.\n\nNote that it's generally recommended to opt for the more strict types (`stockholm.Money`, `stockholm.Number` and `stockholm.Currency`) when possible and the coercion types should be used with caution and is mainly suited for experimentation and early development.\n\n### Conversion for other transport medium (for example Protocol Buffers or JSON)\n\n##### *Easily splittable into `units` and `nanos` for transport in network medium, for example using the [`google.type.Money` protobuf definition](https://github.com/googleapis/googleapis/blob/master/google/type/money.proto) when using Protocol Buffers.*\n\n```python\nfrom stockholm import Money\n\nmoney = Money(\"22583.75382\", \"SEK\")\nmoney.units, money.nanos, money.currency_code\n# (22583, 753820000, 'SEK')\n\n# or vice versa\nMoney(units=22583, nanos=753820000, currency=\"SEK\")\n# <stockholm.Money: \"22583.75382 SEK\">\n```\n\n##### *Monetary amounts can also be exported to `dict` as well as created with `dict` value input, which can be great to for example transport a monetary value in JSON.*\n\n```python\nfrom stockholm import Money\n\nmoney = Money(\"4711.75\", \"SEK\")\ndict(money)  # or by using: money.asdict()\n# {'value': '4711.75 SEK', 'units': 4711, 'nanos': 750000000, 'currency_code': 'SEK'}\n\n# A monetary amount object can be created from a dict either by passing dict directly\n# to the Money() constructor or by using Money.from_dict(dict_input). Not all values\n# needs to be available in the input dict, either \"units\", \"nanos\", \"value\" or \"amount\"\n# should be specified or any combination of them, as long as values would result in the\n# same output monetary value.\nmoney = Money.from_dict({\n    \"value\": \"4711.75 SEK\",\n    \"units\": 4711,\n    \"nanos\": 750000000,\n    \"currency_code\": \"SEK\"\n})\n# <stockholm.Money: \"4711.75 SEK\">\n```\n\nThe `money.asdict()` function can be called with an optional `keys` argument, which can be used to specify a tuple of keys which shuld be used in the returned dict.\n\nThe default behaviour of `money.asdict()` is equivalent to `money.asdict(keys=(\"value\", \"units\", \"nanos\", \"currency_code\"))`.\n\nValues to use in the `keys` tuple for `stockholm.Money` objects are any combination of the following:\n\n| key | description | return type | example |\n| :-- | :---------- | :---------- | -------: |\n| `value` | amount + currency code | `str` | `\"9001.50 USD\"`\n| `units` | units of the amount | `int` | `9001` |\n| `nanos` | number of nano units of the amount | `int` | `500000000` |\n| `currency_code` | currency code if available | `str \\| None` | `\"USD\"` |\n| `currency` | currency code if available | `str \\| None` | `\"USD\"` |\n| `amount` | the monetary amount (excl. currency code) | `str` | `\"9001.50\"` |\n\n```python\nfrom stockholm import Money\n\nMoney(\"4711 USD\").asdict(keys=(\"value\", \"units\", \"nanos\", \"currency_code\"))\n# {'value': '4711.00 USD', 'units': 4711, 'nanos': 0, 'currency_code': 'USD'}\n\nMoney(\"4711 USD\").asdict(keys=(\"amount\", \"currency\"))\n# {'amount': '4711.00', 'currency': 'USD'}\n\nMoney(nanos=10).asdict(keys=(\"value\", \"currency\", \"units\", \"nanos\"))\n# {'value': '0.00000001', 'currency': None, 'units': 0, 'nanos': 10}\n```\n\n##### *Using Protocol Buffers for transporting monetary amounts over the network.*\n\n```python\nfrom stockholm import Money\n\n# By default we're utilizing Google's protobuf message called google.type.Money, however\n# the protobuf class can be overriden with your own if using similar keys and value types.\n# https://github.com/googleapis/googleapis/blob/master/google/type/money.proto\n\nmoney = Money(\"4711.75\", \"SEK\")\nmoney.as_protobuf()\n# This will produce a protobuf object which by default holds values for units, nanos and\n# currency_code as per the google.type.Money protobuf message definition.\n# Use money.as_protobuf(proto_class=YourProtoClass) if you're using custom messages that\n# are not of Google's proto message type.\n#\n# To get the exact byte output produced from the proto class, call their\n# SerailizeToString() function.\nmoney.as_protobuf().SerializeToString()\n# b'\\n\\x03SEK\\x10\\xe7$\\x18\\x80\\xaf\\xd0\\xe5\\x02'\n\n# Of course we can also instantiate a monetary amount object by passing a proto message,\n# either by using the already parsed proto object, or by passing the byte data directly.\n# If no proto_class keyword argument is specified, we'll once again default to\n# google.type.Money.\nmoney = Money.from_protobuf(b'\\n\\x03SEK\\x10\\xe7$\\x18\\x80\\xaf\\xd0\\xe5\\x02')\n# <stockholm.Money: \"4711.75 SEK\">\n\n# In another example we'll build the message just before hand to be extra descriptive\n# of what's happening. The stockholm.MoneyProtobufMessage (or stockholm.protobuf.Money)\n# class is a generated Python representation of the google.type.Money protobuf message\n# definition. You can also use your own custom class.\nfrom stockholm import MoneyProtobufMessage\nmessage = MoneyProtobufMessage()\nmessage.units = 2549\nmessage.nanos = 990000000\nmessage.currency_code = \"USD\"\n# If you're using custom classes that aren't generated from google.type.Money, then pass\n# your generated class as the proto_class keyword argument. In this example, it's not\n# actually needed, since MoneyProtobufMessage is built from google.type.Money definitions.\nmoney = Money.from_protobuf(message, proto_class=MoneyProtobufMessage)\n# <stockholm.Money: \"2549.99 USD\">\nmessage.SerializeToString()\n# b'\\x10\\xf5\\x13\\x18\\x80\\xe7\\x88\\xd8\\x03'\n\n# Usually the byte data may already be parsed from your proto class into your\n# proto objects, and if you're using google.type.Money in your messages you could\n# pass in the object without any additional proto_class keyword.\n#\n# In the following example we have a message that contains a field on position 1\n# named \"remaining_sum\", which in turn holds a google.type.Money value.\n#\n# Let's say the message holds the following as a parsed proto object:\n# remaining_sum {\n#  currency_code: \"USD\"\n#  units: 42\n# }\n#\n# It's binary representation is b'\\n\\x07\\n\\x03USD\\x10*'.\n# And the binary representation of message.remaining_sum is b'\\n\\x03USD\\x10*'.\n#\n# By passing the monetary part of the message (in this case, the field remaining_sum)\n# we can immediately create a monetary amount object which is currency aware.\nmoney = Money.from_protobuf(message.remaining_sum)\n# <stockholm.Money: \"42.00 USD\">\n#\n# Of course this newly instantiated montary amount object can be accessed in many\n# different ways, can use arithmetics like normally, etc.\nmoney.amount\n# Decimal('42.000000000')\nmoney.units\n# 42\nmoney.nanos\n# 0\nmoney.currency\n# \"USD\"\nmoney + 10\n# <stockholm.Money: \"52.00 USD\">\nmoney * 31 - 20 + Money(\"0.50\")\n# <stockholm.Money: \"1282.50 USD\">\n```\n\n##### *Reading or outputting monetary amounts as JSON*\n\n```python\nfrom stockholm import Money\n\n# Outputting key-values as a dict or JSON string. For example great when sending monetary\n# amounts over GraphQL or internal API:s.\nmoney = Money(5767.50, currency=\"EUR\")\n# <stockholm.Money: \"5767.50 EUR\">\n#\n# If no keys keyword argument is specified the default keys will be used, which is\n# value, units, nanos and currency_code.\nmoney.as_json()\n# '{\"value\": \"5767.50 EUR\", \"units\": 5767, \"nanos\": 500000000, \"currency_code\": \"EUR\"}'\n#\n# Besides value, units, nanos and currency_code, the other keys that can be specified\n# are amount and currency (converted to str and equivalent to currency_code in this\n# context).\nmoney.as_json(keys=(\"amount\", \"currency_code\"))\n# '{\"amount\": \"5767.500000000\", \"currency_code\": \"EUR\"}'\n\n# It's also possible directly parse a monetary amount from its incoming JSON string\nMoney.from_json('{\"value\": \"5767.50 EUR\", \"units\": 5767, \"nanos\": 500000000}')\n# <stockholm.Money: \"5767.50 EUR\">\nMoney.from_json('{\"amount\": \"5767.500000000\", \"currency_code\": \"EUR\"}')\n# <stockholm.Money: \"5767.50 EUR\">\n```\n\n#### Parameters of the Money object\n\n```python\nfrom stockholm import Currency, Money\n\n# This is our monetary object, instantiated as 59112.50 EUR using the\n# currency object stockholm.Currency.EUR, which among other things holds data\n# regarding how many decimal digits should normally be printed. A monetary amount\n# in EUR is usually demoninated with two decimal digits.\n\nmoney = Money(\"59112.50\", currency=Currency.EUR)\n# <stockholm.Money: \"59112.50 EUR\">\n\nmoney.amount\n# Decimal('59112.50')\n# Type: decimal.Decimal\n\nmoney.value\n# '59112.50 EUR'\n# Type: string\n\nmoney.units\n# 59112\n# Type: integer\n\nmoney.nanos\n# 500000000\n# Type: integer\n\nmoney.currency_code\n# 'EUR'\n# Type: Either: A string or None\n\nmoney.currency\n# <stockholm.Currency: \"EUR\">\n# Type: Either: a currency object, a string (equivalent to currency_code) or None\n\nmoney.sub_units\n# Decimal('5911250')\n# Type: decimal.Decimal\n\nmoney.asdict()\n# {'value': '59112.50 EUR', 'units': 59112, 'nanos': 500000000, 'currency_code': 'EUR'}\n# Type: dict\n\nmoney.as_string()  # or: str(money)\n# '59112.50 EUR'\n# Type: string\n\nmoney.as_int()  # or: int(money)\n# 59112\n# Type: integer\n\nmoney.as_float()  # or: float(money)\n# 59112.5\n# Type: float\n# Note that using floats may cause you to lose precision. Floats are strongly discouraged.\n\nmoney.is_signed()\n# False\n# Type: boolean\n\nmoney.is_zero()\n# False\n# Type: boolean\n\nmoney.to_integral()\n# <stockholm.Money: \"59113.00 EUR\">\n# Type: stockholm.Money\n\nmoney.amount_as_string(min_decimals=4, max_decimals=7)\n# 59112.5000\n# Type: string\n\nmoney.amount_as_string(min_decimals=0)\n# 59112.5\n# Type: string\n\nmoney.amount_as_string(max_decimals=0)\n# 59113\n# Type: string\n\nmoney.to_currency(currency=\"SEK\")\n# <stockholm.Money: \"59113.50 SEK\">\n# Type: stockholm.Money\n\nmoney.as_json()\n# '{\"value\": \"59112.50 EUR\", \"units\": 59112, \"nanos\": 500000000, \"currency_code\": \"EUR\"}'\n# Type: string\n\nmoney.as_json(keys=(\"amount\", \"currency\"))\n# '{\"amount\": \"59112.50\", \"currency\": \"EUR\"}'\n# Type: string\n\nmoney.as_protobuf()\n# currency_code: \"EUR\"\n# units: 59112\n# nanos: 500000000\n# Type: stockholm.protobuf.money_pb2.Money, generated from proto definitions at\n# https://github.com/googleapis/googleapis/blob/master/google/type/money.proto\n\nmoney.as_protobuf(proto_class=CustomMoneyProtobufMessage)\n# Type: An instance of CustomMoneyProtobufMessage populated with the properties of money\n```\n\n*A simple, yet powerful way of coding with money.*\n\n## Acknowledgements\n\nBuilt with inspiration from https://github.com/carlospalol/money and https://github.com/vimeo/py-money\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Human friendly and flexible package for working with monetary amounts",
    "version": "0.5.7",
    "project_urls": {
        "Homepage": "https://github.com/kalaspuff/stockholm",
        "Repository": "https://github.com/kalaspuff/stockholm"
    },
    "split_keywords": [
        "money",
        "monetary amount",
        "monetary value",
        "currency",
        "formatting",
        "protobuf",
        "protocol buffers",
        "graphql",
        "money graphql",
        "protobuf money",
        "protocol buffers money",
        "json",
        "python money",
        "monetary object",
        "python money class",
        "finance",
        "fintech"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "e387c4c4543781c9459af89942847037a1bfe3ac6843b7e8b1a22507d89606ed",
                "md5": "0fa5251dc4eaa6f0c791c200e5ba1990",
                "sha256": "49ca18676b14b2845b084f9f2d43448d15e895a2fcb107717026e5b55ef2b860"
            },
            "downloads": -1,
            "filename": "stockholm-0.5.7-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "0fa5251dc4eaa6f0c791c200e5ba1990",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8,<4.0",
            "size": 31653,
            "upload_time": "2023-11-23T22:48:04",
            "upload_time_iso_8601": "2023-11-23T22:48:04.157685Z",
            "url": "https://files.pythonhosted.org/packages/e3/87/c4c4543781c9459af89942847037a1bfe3ac6843b7e8b1a22507d89606ed/stockholm-0.5.7-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "2b0c2bf69ec49a1303512d65c4ea953facd0e0486d94603cabaee85be824738d",
                "md5": "778b73cac276df69492503c2d1ce5eba",
                "sha256": "1ac3ee160cec7d2834f13b76e44ae7cc61bd68168c3db4456325818ee3b51333"
            },
            "downloads": -1,
            "filename": "stockholm-0.5.7.tar.gz",
            "has_sig": false,
            "md5_digest": "778b73cac276df69492503c2d1ce5eba",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8,<4.0",
            "size": 38536,
            "upload_time": "2023-11-23T22:48:07",
            "upload_time_iso_8601": "2023-11-23T22:48:07.568925Z",
            "url": "https://files.pythonhosted.org/packages/2b/0c/2bf69ec49a1303512d65c4ea953facd0e0486d94603cabaee85be824738d/stockholm-0.5.7.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-11-23 22:48:07",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "kalaspuff",
    "github_project": "stockholm",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "stockholm"
}
        
Elapsed time: 0.17789s