Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-django-money for
openSUSE:Factory checked in at 2022-05-12 23:00:55
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-django-money (Old)
and /work/SRC/openSUSE:Factory/.python-django-money.new.1538 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-django-money"
Thu May 12 23:00:55 2022 rev:3 rq:976603 version:2.1.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-django-money/python-django-money.changes
2021-05-17 18:46:05.164427245 +0200
+++
/work/SRC/openSUSE:Factory/.python-django-money.new.1538/python-django-money.changes
2022-05-12 23:01:55.972923482 +0200
@@ -1,0 +2,30 @@
+Thu May 12 11:45:54 UTC 2022 - John Vandenberg <[email protected]>
+
+- Update to v2.1.1
+ * Make Django REST Framework integration always raise lower-level
+ errors as ValidationError.
+ * False positives in Migration changes, improvements to
+ MoneyField.deconstruct.
+- from v2.1
+ * Add support for Django 3.2.
+ * Drop support for Django 1.11, 2.1 and 3.0.
+ * Drop support for Python 3.5.
+- from v2.0.3
+ * Inconsistent Money._copy_attributes behaviour when non-Money
+ instances are involved.
+- from v2.0.2
+ * Inconsistent Money._copy_attributes behaviour.
+- from v2.0.1
+ * Invalid deprecation warning behavior.
+- from v2.0
+ * New setting CURRENCY_CODE_MAX_LENGTH configures default
+ max_length for MoneyField and exchange app models.
+ * Update py-moneyed to >=1.2,<2. It uses babel to format Money,
+ which formats it differently than py-moneyed<1.
+ * Money.decimal_places_display to be removed in django-money 3.0.
+ * CURRENCY_DECIMAL_PLACES_DISPLAY to be removed in django-money 3.0.
+- Add patches for py-moneyed v2 support
+ * merged_pr_657.patch
+ * pr_638.patch
+
+-------------------------------------------------------------------
Old:
----
django-money-1.3.1.tar.gz
New:
----
django-money-2.1.1.tar.gz
merged_pr_657.patch
pr_638.patch
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-django-money.spec ++++++
--- /var/tmp/diff_new_pack.5AoRI8/_old 2022-05-12 23:01:56.496924186 +0200
+++ /var/tmp/diff_new_pack.5AoRI8/_new 2022-05-12 23:01:56.504924196 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-django-money
#
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2022 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,13 +19,15 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-django-money
-Version: 1.3.1
+Version: 2.1.1
Release: 0
Summary: Django support for using money and currency fields
License: BSD-3-Clause
Group: Development/Languages/Python
URL: https://github.com/django-money/django-money
Source:
https://github.com/django-money/django-money/archive/%{version}.tar.gz#/django-money-%{version}.tar.gz
+Patch0: merged_pr_657.patch
+Patch1: pr_638.patch
BuildRequires: %{python_module setuptools}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
@@ -52,6 +54,8 @@
%prep
%setup -q -n django-money-%{version}
+%patch0 -p1
+%patch1 -p1
%build
%python_build
@@ -63,11 +67,12 @@
%check
export DJANGO_SETTINGS_MODULE=tests.settings
# we don't have python-mixer and it is needed only for tests
-%pytest -k "not mixer"
+%pytest -k "not (mixer or test_no_deprecation_warning)"
%files %{python_files}
%doc README.rst
%license LICENSE.txt
-%{python_sitelib}/*
+%{python_sitelib}/djmoney/
+%{python_sitelib}/django_money*/
%changelog
++++++ django-money-1.3.1.tar.gz -> django-money-2.1.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/.github/workflows/main.yml
new/django-money-2.1.1/.github/workflows/main.yml
--- old/django-money-1.3.1/.github/workflows/main.yml 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/.github/workflows/main.yml 2022-01-02
18:39:41.000000000 +0100
@@ -17,6 +17,7 @@
- run: pip install pre-commit
- run: pre-commit run --all-files
+
docs:
name: docs
runs-on: ubuntu-latest
@@ -27,89 +28,47 @@
- uses: actions/setup-python@v2
with:
- python-version: 3.7
+ python-version: 3.9
- run: pip install tox
- name: Run docs tox job
run: tox -e docs
- lint:
- name: lint
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- with:
- fetch-depth: 1
-
- - uses: actions/setup-python@v2
- with:
- python-version: 3.7
-
- - run: pip install tox
-
- - name: Run lint tox job
- run: tox -e lint
tests:
strategy:
matrix:
include:
- python: pypy3
- tox_env: django111-pypy3
- - python: pypy3
- tox_env: django21-pypy3
- - python: pypy3
tox_env: django22-pypy3
- python: pypy3
- tox_env: django30-pypy3
- - python: pypy3
tox_env: django31-pypy3
- - python: 3.5
- tox_env: django111-py35
- - python: 3.5
- tox_env: django21-py35
- - python: 3.5
- tox_env: django22-py35
- - python: 3.6
- tox_env: django111-py36
- - python: 3.6
- tox_env: django21-py36
- python: 3.6
tox_env: django22-py36
- python: 3.6
- tox_env: django30-py36
- - python: 3.6
tox_env: django31-py36
- python: 3.6
- tox_env: django_master-py36
- - python: 3.6
tox_env: no_rest_framework
- python: 3.7
- tox_env: django21-py37
- - python: 3.7
tox_env: django22-py37
- python: 3.7
- tox_env: django30-py37
- - python: 3.7
tox_env: django31-py37
- - python: 3.7
- tox_env: django_master-py37
- python: 3.8
tox_env: django22-py38
- python: 3.8
- tox_env: django30-py38
- - python: 3.8
tox_env: django31-py38
- python: 3.8
- tox_env: django_master-py38
+ tox_env: django32-py38
+ - python: 3.8
+ tox_env: django_main-py38
- python: 3.9
tox_env: django22-py39
- python: 3.9
- tox_env: django30-py39
- - python: 3.9
tox_env: django31-py39
- python: 3.9
- tox_env: django_master-py39
+ tox_env: django32-py39
+ - python: 3.9
+ tox_env: django_main-py39
name: ${{ matrix.tox_env }}
runs-on: ubuntu-latest
steps:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/.pre-commit-config.yaml
new/django-money-2.1.1/.pre-commit-config.yaml
--- old/django-money-1.3.1/.pre-commit-config.yaml 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/.pre-commit-config.yaml 2022-01-02
18:39:41.000000000 +0100
@@ -1,6 +1,6 @@
repos:
- repo: git://github.com/pre-commit/pre-commit-hooks
- rev: v3.3.0
+ rev: v3.4.0
hooks:
- id: trailing-whitespace
- id: check-yaml
@@ -11,26 +11,39 @@
args:
- --remove
+- repo: https://github.com/asottile/pyupgrade
+ rev: v2.12.0
+ hooks:
+ - id: pyupgrade
+ args:
+ - --py36-plus
+
- repo: https://github.com/asottile/seed-isort-config
rev: v2.2.0
hooks:
- id: seed-isort-config
- repo: https://github.com/pre-commit/mirrors-isort
- rev: v5.6.4
+ rev: v5.8.0
hooks:
- id: isort
- repo: https://gitlab.com/pycqa/flake8
- rev: 3.8.4
+ rev: 3.9.1
hooks:
- id: flake8
exclude: ^docs
- repo: https://github.com/myint/rstcheck
- rev: master
+ rev: 3f92957
hooks:
- id: rstcheck
additional_dependencies:
- sphinx==3.1.2
args: [--ignore-directives=code]
+
+- repo: https://github.com/psf/black
+ rev: 20.8b1
+ hooks:
+ - id: black
+ exclude: ^docs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/README.rst
new/django-money-2.1.1/README.rst
--- old/django-money-1.3.1/README.rst 2021-02-04 10:32:33.000000000 +0100
+++ new/django-money-2.1.1/README.rst 2022-01-02 18:39:41.000000000 +0100
@@ -5,8 +5,8 @@
:target: https://github.com/django-money/django-money/actions
:alt: Build Status
-.. image::
http://codecov.io/github/django-money/django-money/coverage.svg?branch=master
- :target: http://codecov.io/github/django-money/django-money?branch=master
+.. image::
http://codecov.io/github/django-money/django-money/coverage.svg?branch=main
+ :target: http://codecov.io/github/django-money/django-money?branch=main
:alt: Coverage Status
.. image:: https://readthedocs.org/projects/django-money/badge/?version=latest
@@ -17,16 +17,16 @@
:target: https://pypi.python.org/pypi/django-money
:alt: PyPI
-A little Django app that uses ``py-moneyed`` to add support for Money
+A little Django app that uses `py-moneyed
<https://github.com/py-moneyed/py-moneyed>`__ to add support for Money
fields in your models and forms.
-* Django versions supported: 1.11, 2.1, 2.2, 3.0, 3.1
-* Python versions supported: 3.5, 3.6, 3.7, 3.8, 3.9
+* Django versions supported: 2.2, 3.1, 3.2
+* Python versions supported: 3.6, 3.7, 3.8, 3.9
* PyPy versions supported: PyPy3
If you need support for older versions of Django and Python, please refer to
older releases mentioned in `the release notes
<https://django-money.readthedocs.io/en/latest/changes.html>`__.
-Through the dependency ``py-moneyed``, ``django-money`` gets:
+Through the dependency `py-moneyed
<https://github.com/py-moneyed/py-moneyed>`__, ``django-money`` gets:
* Support for proper Money value handling (using the standard Money
design pattern)
@@ -42,7 +42,7 @@
$ pip install django-money
-This automatically installs ``py-moneyed`` v0.8 (or later).
+This automatically installs ``py-moneyed`` v1.2 (or later).
Add ``djmoney`` to your ``INSTALLED_APPS``. This is required so that money
field are displayed correctly in the admin.
@@ -94,6 +94,11 @@
BankAccount.objects.filter(balance__gt=Money(1, 'USD'))
# Returns the "account" object
+The default currency code length is `3` but you can change it with the
`CURRENCY_CODE_MAX_LENGTH` setting.
+
+Caution: this setting also affects the initial migration of the `exchange`
plugin, so changing it after running
+the initial migration has no effect. (You'd need to `manage migrate exchange
zero` and migrate again if you want
+to change it).
Field validation
----------------
@@ -141,15 +146,12 @@
Currencies are listed on moneyed, and this modules use this to provide a
choice list on the admin, also for validation.
-To add a new currency available on all the project, you can simple add
-this two lines on your ``settings.py`` file
+To add a new currency available on all the project, you can simply add
+these few lines to your ``settings.py`` file:
.. code:: python
import moneyed
- from moneyed.localization import _FORMATTER
- from decimal import ROUND_HALF_EVEN
-
BOB = moneyed.add_currency(
code='BOB',
@@ -158,20 +160,6 @@
countries=('BOLIVIA', )
)
- # Currency Formatter will output 2.000,00 Bs.
- _FORMATTER.add_sign_definition(
- 'default',
- BOB,
- prefix=u'Bs. '
- )
-
- _FORMATTER.add_formatting_definition(
- 'es_BO',
- group_size=3, group_separator=".", decimal_point=",",
- positive_sign="", trailing_positive_sign="",
- negative_sign="-", trailing_negative_sign="",
- rounding_method=ROUND_HALF_EVEN
- )
To restrict the currencies listed on the project set a ``CURRENCIES``
variable with a list of Currency codes on ``settings.py``
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/djmoney/__init__.py
new/django-money-2.1.1/djmoney/__init__.py
--- old/django-money-1.3.1/djmoney/__init__.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/djmoney/__init__.py 2022-01-02 18:39:41.000000000
+0100
@@ -1,2 +1,2 @@
-__version__ = "1.3.1"
+__version__ = "2.1.1"
default_app_config = "djmoney.apps.MoneyConfig"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/djmoney/apps.py
new/django-money-2.1.1/djmoney/apps.py
--- old/django-money-1.3.1/djmoney/apps.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/djmoney/apps.py 2022-01-02 18:39:41.000000000
+0100
@@ -3,6 +3,7 @@
class MoneyConfig(AppConfig):
name = "djmoney"
+ default_auto_field = "django.db.models.AutoField"
def ready(self):
try:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-money-1.3.1/djmoney/contrib/django_rest_framework/fields.py
new/django-money-2.1.1/djmoney/contrib/django_rest_framework/fields.py
--- old/django-money-1.3.1/djmoney/contrib/django_rest_framework/fields.py
2021-02-04 10:32:33.000000000 +0100
+++ new/django-money-2.1.1/djmoney/contrib/django_rest_framework/fields.py
2022-01-02 18:39:41.000000000 +0100
@@ -1,4 +1,5 @@
from django.core.validators import MaxValueValidator, MinValueValidator
+from django.utils.translation import gettext_lazy as _
from rest_framework.fields import empty
from rest_framework.serializers import DecimalField, ModelSerializer
@@ -7,6 +8,20 @@
from djmoney.models.validators import MaxMoneyValidator, MinMoneyValidator
from djmoney.money import Money
from djmoney.utils import MONEY_CLASSES, get_currency_field_name
+from moneyed.classes import CurrencyDoesNotExist
+
+
+class _PrimitiveMoney:
+ """
+ A container for ``Money`` data that does not do any validation of said
data.
+ It conveniently holds the amount and currency attributes to ease
transformation into a valid ``Money`` instance.
+ """
+
+ __slots__ = ("amount", "currency")
+
+ def __init__(self, amount, currency):
+ self.amount = amount
+ self.currency = currency
class MoneyField(DecimalField):
@@ -15,6 +30,10 @@
does decimal's validation during transformation to native value.
"""
+ default_error_messages = {
+ "invalid_currency": _("{currency!r} is not a valid currency"),
+ }
+
def __init__(self, *args, **kwargs):
self.default_currency = kwargs.pop("default_currency", None)
super().__init__(*args, **kwargs)
@@ -36,16 +55,20 @@
return super().to_representation(obj)
def to_internal_value(self, data):
- if isinstance(data, MONEY_CLASSES):
+ if isinstance(data, MONEY_CLASSES + (_PrimitiveMoney,)):
amount = super().to_internal_value(data.amount)
- return Money(amount, data.currency)
+ try:
+ return Money(amount, data.currency)
+ except CurrencyDoesNotExist:
+ self.fail("invalid_currency", currency=data.currency)
+
return super().to_internal_value(data)
def get_value(self, data):
amount = super().get_value(data)
currency = data.get(get_currency_field_name(self.field_name),
self.default_currency)
if currency and amount is not None and not isinstance(amount,
MONEY_CLASSES) and amount is not empty:
- return Money(amount, currency)
+ return _PrimitiveMoney(amount=amount, currency=currency)
return amount
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-money-1.3.1/djmoney/contrib/exchange/migrations/0001_initial.py
new/django-money-2.1.1/djmoney/contrib/exchange/migrations/0001_initial.py
--- old/django-money-1.3.1/djmoney/contrib/exchange/migrations/0001_initial.py
2021-02-04 10:32:33.000000000 +0100
+++ new/django-money-2.1.1/djmoney/contrib/exchange/migrations/0001_initial.py
2022-01-02 18:39:41.000000000 +0100
@@ -3,6 +3,8 @@
import django.db.models.deletion
from django.db import migrations, models
+from djmoney.settings import CURRENCY_CODE_MAX_LENGTH
+
class Migration(migrations.Migration):
@@ -16,14 +18,14 @@
fields=[
("name", models.CharField(max_length=255, primary_key=True,
serialize=False)),
("last_update", models.DateTimeField(auto_now=True)),
- ("base_currency", models.CharField(max_length=3)),
+ ("base_currency",
models.CharField(max_length=CURRENCY_CODE_MAX_LENGTH)),
],
),
migrations.CreateModel(
name="Rate",
fields=[
("id", models.AutoField(auto_created=True, primary_key=True,
serialize=False, verbose_name="ID")),
- ("currency", models.CharField(max_length=3)),
+ ("currency",
models.CharField(max_length=CURRENCY_CODE_MAX_LENGTH)),
("value", models.DecimalField(decimal_places=6,
max_digits=20)),
(
"backend",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-money-1.3.1/djmoney/contrib/exchange/models.py
new/django-money-2.1.1/djmoney/contrib/exchange/models.py
--- old/django-money-1.3.1/djmoney/contrib/exchange/models.py 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/djmoney/contrib/exchange/models.py 2022-01-02
18:39:41.000000000 +0100
@@ -4,7 +4,7 @@
from django.db import models
from django.utils.module_loading import import_string
-from djmoney.settings import EXCHANGE_BACKEND, RATES_CACHE_TIMEOUT
+from djmoney.settings import CURRENCY_CODE_MAX_LENGTH, EXCHANGE_BACKEND,
RATES_CACHE_TIMEOUT
from .exceptions import MissingRate
@@ -12,7 +12,7 @@
class ExchangeBackend(models.Model):
name = models.CharField(max_length=255, primary_key=True)
last_update = models.DateTimeField(auto_now=True)
- base_currency = models.CharField(max_length=3)
+ base_currency = models.CharField(max_length=CURRENCY_CODE_MAX_LENGTH)
def __str__(self):
return self.name
@@ -22,7 +22,7 @@
class Rate(models.Model):
- currency = models.CharField(max_length=3)
+ currency = models.CharField(max_length=CURRENCY_CODE_MAX_LENGTH)
value = models.DecimalField(max_digits=20, decimal_places=6)
backend = models.ForeignKey(ExchangeBackend, on_delete=models.CASCADE,
related_name="rates")
@@ -42,7 +42,7 @@
"""
if backend is None:
backend = get_default_backend_name()
- key = "djmoney:get_rate:%s:%s:%s" % (source, target, backend)
+ key = f"djmoney:get_rate:{source}:{target}:{backend}"
result = cache.get(key)
if result is not None:
return result
@@ -57,7 +57,7 @@
return 1
rates = Rate.objects.filter(currency__in=(source, target),
backend=backend).select_related("backend")
if not rates:
- raise MissingRate("Rate %s -> %s does not exist" % (source, target))
+ raise MissingRate(f"Rate {source} -> {target} does not exist")
if len(rates) == 1:
return _try_to_get_rate_directly(source, target, rates[0])
return _get_rate_via_base(rates, target)
@@ -74,7 +74,7 @@
elif rate.backend.base_currency == target and rate.currency == source:
return 1 / rate.value
# Case when target or source is not a base currency
- raise MissingRate("Rate %s -> %s does not exist" % (source, target))
+ raise MissingRate(f"Rate {source} -> {target} does not exist")
def _get_rate_via_base(rates, target):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/djmoney/forms/fields.py
new/django-money-2.1.1/djmoney/forms/fields.py
--- old/django-money-1.3.1/djmoney/forms/fields.py 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/djmoney/forms/fields.py 2022-01-02
18:39:41.000000000 +0100
@@ -32,7 +32,7 @@
min_value=min_value,
max_digits=max_digits,
decimal_places=decimal_places,
- **kwargs
+ **kwargs,
)
currency_field = ChoiceField(choices=currency_choices)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/djmoney/models/fields.py
new/django-money-2.1.1/djmoney/models/fields.py
--- old/django-money-1.3.1/djmoney/models/fields.py 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/djmoney/models/fields.py 2022-01-02
18:39:41.000000000 +0100
@@ -14,7 +14,7 @@
from moneyed import Money as OldMoney
from .._compat import setup_managers
-from ..settings import CURRENCY_CHOICES, DECIMAL_PLACES, DEFAULT_CURRENCY
+from ..settings import CURRENCY_CHOICES, CURRENCY_CODE_MAX_LENGTH,
DECIMAL_PLACES, DEFAULT_CURRENCY
from ..utils import MONEY_CLASSES, get_currency_field_name, prepare_expression
@@ -149,7 +149,7 @@
def __init__(self, price_field=None, default=DEFAULT_CURRENCY, **kwargs):
if isinstance(default, Currency):
default = default.code
- kwargs.setdefault("max_length", 3)
+ kwargs.setdefault("max_length", CURRENCY_CODE_MAX_LENGTH)
self.price_field = price_field
super().__init__(default=default, **kwargs)
@@ -170,7 +170,7 @@
default=NOT_PROVIDED,
default_currency=DEFAULT_CURRENCY,
currency_choices=CURRENCY_CHOICES,
- currency_max_length=3,
+ currency_max_length=CURRENCY_CODE_MAX_LENGTH,
currency_field_name=None,
money_descriptor_class=MoneyFieldProxy,
**kwargs
@@ -298,12 +298,17 @@
if self._has_default:
kwargs["default"] = self.default.amount
- if self.default_currency is not None and self.default_currency !=
DEFAULT_CURRENCY:
- kwargs["default_currency"] = str(self.default_currency)
+ if self.default_currency != DEFAULT_CURRENCY:
+ if self.default_currency is not None:
+ kwargs["default_currency"] = str(self.default_currency)
+ else:
+ kwargs["default_currency"] = None
if self.currency_choices != CURRENCY_CHOICES:
kwargs["currency_choices"] = self.currency_choices
if self.currency_field_name:
kwargs["currency_field_name"] = self.currency_field_name
+ if self.currency_max_length != CURRENCY_CODE_MAX_LENGTH:
+ kwargs["currency_max_length"] = self.currency_max_length
return name, path, args, kwargs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/djmoney/money.py
new/django-money-2.1.1/djmoney/money.py
--- old/django-money-1.3.1/djmoney/money.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/djmoney/money.py 2022-01-02 18:39:41.000000000
+0100
@@ -1,3 +1,7 @@
+import warnings
+from functools import partial
+from types import MappingProxyType
+
from django.conf import settings
from django.db.models import F
from django.utils import translation
@@ -5,14 +9,21 @@
from django.utils.html import avoid_wrapping, conditional_escape
from django.utils.safestring import mark_safe
+import moneyed.l10n
+import moneyed.localization
from moneyed import Currency, Money as DefaultMoney
-from moneyed.localization import _FORMATTER, format_money
-from .settings import DECIMAL_PLACES, DECIMAL_PLACES_DISPLAY
+from .settings import DECIMAL_PLACES, DECIMAL_PLACES_DISPLAY,
IS_DECIMAL_PLACES_DISPLAY_SET, MONEY_FORMAT
__all__ = ["Money", "Currency"]
+_warn_decimal_places_display_deprecated = partial(
+ warnings.warn,
+ "`Money.decimal_places_display` is deprecated and will be removed in
django-money 3.0.",
+ DeprecationWarning,
+)
+
@deconstructible
class Money(DefaultMoney):
@@ -22,21 +33,25 @@
use_l10n = None
- def __init__(self, *args, decimal_places_display=None, **kwargs):
+ def __init__(self, *args, decimal_places_display=None,
format_options=None, **kwargs):
self.decimal_places = kwargs.pop("decimal_places", DECIMAL_PLACES)
self._decimal_places_display = decimal_places_display
+ if decimal_places_display is not None:
+ _warn_decimal_places_display_deprecated()
+ self.format_options = MappingProxyType(format_options) if
format_options is not None else None
super().__init__(*args, **kwargs)
@property
def decimal_places_display(self):
+ _warn_decimal_places_display_deprecated()
if self._decimal_places_display is None:
return DECIMAL_PLACES_DISPLAY.get(self.currency.code,
self.decimal_places)
-
return self._decimal_places_display
@decimal_places_display.setter
def decimal_places_display(self, value):
""" Set number of digits being displayed - `None` resets to
`DECIMAL_PLACES_DISPLAY` setting """
+ _warn_decimal_places_display_deprecated()
self._decimal_places_display = value
def _copy_attributes(self, source, target):
@@ -50,9 +65,15 @@
When it comes to what number of decimal places to choose, we take the
maximum number.
"""
- for attribute_name in ("decimal_places", "decimal_places_display"):
- value = max([getattr(candidate, attribute_name, 0) for candidate
in (self, source)])
- setattr(target, attribute_name, value)
+ for attribute_name in ("decimal_places", "_decimal_places_display"):
+ selection = [
+ getattr(candidate, attribute_name, None)
+ for candidate in (self, source)
+ if getattr(candidate, attribute_name, None) is not None
+ ]
+ if selection:
+ value = max(selection)
+ setattr(target, attribute_name, value)
def __add__(self, other):
if isinstance(other, F):
@@ -97,13 +118,21 @@
return self.use_l10n
def __str__(self):
- kwargs = {"money": self, "decimal_places": self.decimal_places_display}
- if self.is_localized:
- locale = get_current_locale()
- if locale:
- kwargs["locale"] = locale
-
- return format_money(**kwargs)
+ if self._decimal_places_display is not None or
IS_DECIMAL_PLACES_DISPLAY_SET:
+ kwargs = {"money": self, "decimal_places":
self.decimal_places_display}
+ if self.is_localized:
+ locale = get_current_locale(for_babel=False)
+ if locale:
+ kwargs["locale"] = locale
+ return moneyed.localization.format_money(**kwargs)
+ format_options = {
+ **MONEY_FORMAT,
+ **(self.format_options or {}),
+ }
+ locale = get_current_locale()
+ if locale:
+ format_options["locale"] = locale
+ return moneyed.l10n.format_money(self, **format_options)
def __html__(self):
return mark_safe(avoid_wrapping(conditional_escape(str(self))))
@@ -146,16 +175,19 @@
__rmul__ = __mul__
-def get_current_locale():
+def get_current_locale(for_babel=True):
# get_language can return None starting from Django 1.8
language = translation.get_language() or settings.LANGUAGE_CODE
locale = translation.to_locale(language)
- if locale.upper() in _FORMATTER.formatting_definitions:
+ if for_babel:
+ return locale
+
+ if locale.upper() in
moneyed.localization._FORMATTER.formatting_definitions:
return locale
- locale = ("%s_%s" % (locale, locale)).upper()
- if locale in _FORMATTER.formatting_definitions:
+ locale = f"{locale}_{locale}".upper()
+ if locale in moneyed.localization._FORMATTER.formatting_definitions:
return locale
return ""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/djmoney/serializers.py
new/django-money-2.1.1/djmoney/serializers.py
--- old/django-money-1.3.1/djmoney/serializers.py 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/djmoney/serializers.py 2022-01-02
18:39:41.000000000 +0100
@@ -45,7 +45,9 @@
continue
field = Model._meta.get_field(field_name)
if isinstance(field, MoneyField) and field_value is not None:
- money_fields[field_name] = Money(field_value,
obj["fields"][get_currency_field_name(field_name)])
+ money_fields[field_name] = Money(
+ field_value,
obj["fields"][get_currency_field_name(field_name, field)]
+ )
else:
fields[field_name] = field_value
obj["fields"] = fields
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/djmoney/settings.py
new/django-money-2.1.1/djmoney/settings.py
--- old/django-money-1.3.1/djmoney/settings.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/djmoney/settings.py 2022-01-02 18:39:41.000000000
+0100
@@ -1,4 +1,6 @@
import operator
+import warnings
+from types import MappingProxyType
from django.conf import settings
@@ -23,9 +25,14 @@
CURRENCY_CHOICES.sort(key=operator.itemgetter(1, 0))
DECIMAL_PLACES = getattr(settings, "CURRENCY_DECIMAL_PLACES", 2)
-DECIMAL_PLACES_DISPLAY = getattr(
- settings, "CURRENCY_DECIMAL_PLACES_DISPLAY", {currency[0]: DECIMAL_PLACES
for currency in CURRENCY_CHOICES}
-)
+_decimal_display_value = getattr(settings, "CURRENCY_DECIMAL_PLACES_DISPLAY",
None)
+if _decimal_display_value is not None:
+ warnings.warn(
+ "`CURRENCY_DECIMAL_PLACES_DISPLAY` is deprecated and will be removed
in django-money 3.0.",
+ DeprecationWarning,
+ )
+DECIMAL_PLACES_DISPLAY = _decimal_display_value or {currency[0]:
DECIMAL_PLACES for currency in CURRENCY_CHOICES}
+IS_DECIMAL_PLACES_DISPLAY_SET = _decimal_display_value is not None
OPEN_EXCHANGE_RATES_URL = getattr(settings, "OPEN_EXCHANGE_RATES_URL",
"https://openexchangerates.org/api/latest.json")
OPEN_EXCHANGE_RATES_APP_ID = getattr(settings, "OPEN_EXCHANGE_RATES_APP_ID",
None)
@@ -34,3 +41,7 @@
BASE_CURRENCY = getattr(settings, "BASE_CURRENCY", "USD")
EXCHANGE_BACKEND = getattr(settings, "EXCHANGE_BACKEND",
"djmoney.contrib.exchange.backends.OpenExchangeRatesBackend")
RATES_CACHE_TIMEOUT = getattr(settings, "RATES_CACHE_TIMEOUT", 600)
+
+CURRENCY_CODE_MAX_LENGTH = getattr(settings, "CURRENCY_CODE_MAX_LENGTH", 3)
+
+MONEY_FORMAT = MappingProxyType(getattr(settings, "MONEY_FORMAT", {}))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/docs/changes.rst
new/django-money-2.1.1/docs/changes.rst
--- old/django-money-1.3.1/docs/changes.rst 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/docs/changes.rst 2022-01-02 18:39:41.000000000
+0100
@@ -1,9 +1,67 @@
Changelog
=========
-`Unreleased`_ - TBD
+`2.1.1`_ - 2022-01-02
+---------------------
+
+**Changed**
+
+- Renamed ``master`` branch to ``main`` (`benjaoming`_)
+
+**Fixed**
+
+- Make Django REST Framework integration always raise lower-level errors as
``ValidationError``. `#601`_, `#637`_ (`flaeppe`_)
+- False positives in Migration changes, improvements to
``MoneyField.deconstruct``. `#646`_, `#648`_ (`flaeppe`_)
+
+`2.1`_ - 2021-09-17
-------------------
+**Added**
+
+- Add support for Django 3.2. `#612`_ (`antonagestam`_)
+
+**Removed**
+
+- Drop support for Django 1.11, 2.1 and 3.0. `#612`_ (`antonagestam`_)
+- Drop support for Python 3.5. `#612`_ (`antonagestam`_)
+
+`2.0.3`_ - 2021-09-04
+---------------------
+
+**Fixed**
+
+- Inconsistent ``Money._copy_attributes`` behaviour when non-``Money``
instances are involved. `#630`_ (`tned73`_)
+
+`2.0.2`_ - 2021-09-04
+---------------------
+
+**Fixed**
+
+- Inconsistent ``Money._copy_attributes`` behaviour. `#629`_ (`tned73`_)
+
+`2.0.1`_ - 2021-07-09
+---------------------
+
+**Fixed**
+
+- Invalid deprecation warning behavior. `#624`_ (`nerdoc`_)
+
+`2.0`_ - 2021-05-23
+-------------------
+
+**Added**
+
+- New setting ``CURRENCY_CODE_MAX_LENGTH`` configures default max_length for
MoneyField and ``exchange`` app models.
+
+**Changed**
+
+- BREAKING: Update ``py-moneyed`` to ``>=1.2,<2``. It uses ``babel`` to format
``Money``, which formats it differently than ``py-moneyed<1``. `#567`_
(`antonagestam`_)
+
+**Deprecated**
+
+- ``Money.decimal_places_display`` will be removed in django-money 3.0.
+- ``CURRENCY_DECIMAL_PLACES_DISPLAY`` will be removed in django-money 3.0.
+
`1.3.1`_ - 2021-02-04
---------------------
@@ -651,7 +709,14 @@
- Initial public release
-.. _Unreleased:
https:///github.com/django-money/django-money/compare/1.3.1...HEAD
+# .. _Unreleased:
https:///github.com/django-money/django-money/compare/2.1.1...HEAD
+
+.. _2.1.1: https:///github.com/django-money/django-money/compare/2.1...2.1.1
+.. _2.1: https:///github.com/django-money/django-money/compare/2.0.3...2.1
+.. _2.0.3: https://github.com/django-money/django-money/compare/2.0.2...2.0.3
+.. _2.0.2: https://github.com/django-money/django-money/compare/2.0.1...2.0.2
+.. _2.0.1: https://github.com/django-money/django-money/compare/2.0...2.0.1
+.. _2.0: https://github.com/django-money/django-money/compare/1.3.1...2.0
.. _1.3.1: https://github.com/django-money/django-money/compare/1.3...1.3.1
.. _1.3: https://github.com/django-money/django-money/compare/1.2.2...1.3
.. _1.2.2: https://github.com/django-money/django-money/compare/1.2.1...1.2.2
@@ -708,12 +773,21 @@
.. _0.3: https://github.com/django-money/django-money/compare/0.2...0.3
.. _0.2:
https://github.com/django-money/django-money/compare/0.2...a6d90348085332a393abb40b86b5dd9505489b04
+.. _#648: https://github.com/django-money/django-money/issues/648
+.. _#646: https://github.com/django-money/django-money/issues/646
+.. _#637: https://github.com/django-money/django-money/issues/637
+.. _#630: https://github.com/django-money/django-money/pull/630
+.. _#629: https://github.com/django-money/django-money/pull/629
+.. _#624: https://github.com/django-money/django-money/issues/624
+.. _#612: https://github.com/django-money/django-money/pull/612
.. _#603: https://github.com/django-money/django-money/issues/603
+.. _#601: https://github.com/django-money/django-money/issues/601
.. _#595: https://github.com/django-money/django-money/issues/595
.. _#593: https://github.com/django-money/django-money/issues/593
.. _#586: https://github.com/django-money/django-money/issues/586
.. _#585: https://github.com/django-money/django-money/pull/585
.. _#583: https://github.com/django-money/django-money/issues/583
+.. _#567: https://github.com/django-money/django-money/issues/567
.. _#553: https://github.com/django-money/django-money/issues/553
.. _#541: https://github.com/django-money/django-money/issues/541
.. _#534: https://github.com/django-money/django-money/issues/534
@@ -825,6 +899,7 @@
.. _akumria: https://github.com/akumria
.. _alexhayes: https://github.com/alexhayes
.. _andytwoods: https://github.com/andytwoods
+.. _antonagestam: https://github.com/antonagestam
.. _arthurk: https://github.com/arthurk
.. _astutejoe: https://github.com/astutejoe
.. _benjaoming: https://github.com/benjaoming
@@ -840,6 +915,7 @@
.. _eriktelepovsky: https://github.com/eriktelepovsky
.. _evenicoulddoit: https://github.com/evenicoulddoit
.. _f213: https://github.com/f213
+.. _flaeppe: https://github.com/flaeppe
.. _Formulka: https://github.com/Formulka
.. _glarrain: https://github.com/glarrain
.. _graik: https://github.com/graik
@@ -866,6 +942,7 @@
.. _msgre: https://github.com/msgre
.. _mstarostik: https://github.com/mstarostik
.. _niklasb: https://github.com/niklasb
+.. _nerdoc: https://github.com/nerdoc
.. _pjdelport: https://github.com/pjdelport
.. _plumdog: https://github.com/plumdog
.. _rach: https://github.com/rach
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/docs/conf.py
new/django-money-2.1.1/docs/conf.py
--- old/django-money-1.3.1/docs/conf.py 2021-02-04 10:32:33.000000000 +0100
+++ new/django-money-2.1.1/docs/conf.py 2022-01-02 18:39:41.000000000 +0100
@@ -52,9 +52,9 @@
master_doc = 'index'
# General information about the project.
-project = u'Django-money'
-copyright = u'2016, Jacob Hansson'
-author = u'Jacob Hansson'
+project = 'Django-money'
+copyright = '2016, Jacob Hansson'
+author = 'Jacob Hansson'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
@@ -227,8 +227,8 @@
# (source start file, target name, title,
# author, documentclass [howto, manual, or own class]).
latex_documents = [
- (master_doc, 'Django-money.tex', u'Django-money Documentation',
- u'Jacob Hansson', 'manual'),
+ (master_doc, 'Django-money.tex', 'Django-money Documentation',
+ 'Jacob Hansson', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
@@ -257,7 +257,7 @@
# One entry per manual page. List of tuples
# (source start file, name, description, authors, manual section).
man_pages = [
- (master_doc, 'django-money', u'Django-money Documentation',
+ (master_doc, 'django-money', 'Django-money Documentation',
[author], 1)
]
@@ -271,7 +271,7 @@
# (source start file, target name, title, author,
# dir menu entry, description, category)
texinfo_documents = [
- (master_doc, 'Django-money', u'Django-money Documentation',
+ (master_doc, 'Django-money', 'Django-money Documentation',
author, 'Django-money', 'One line description of project.',
'Miscellaneous'),
]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/pyproject.toml
new/django-money-2.1.1/pyproject.toml
--- old/django-money-1.3.1/pyproject.toml 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/pyproject.toml 2022-01-02 18:39:41.000000000
+0100
@@ -1,3 +1,7 @@
[build-system]
requires = ["setuptools >= 40.6.0", "wheel"]
build-backend = "setuptools.build_meta"
+
+[tool.black]
+line-length = 120
+target-version = ["py35"]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/pytest.ini
new/django-money-2.1.1/pytest.ini
--- old/django-money-1.3.1/pytest.ini 2021-02-04 10:32:33.000000000 +0100
+++ new/django-money-2.1.1/pytest.ini 2022-01-02 18:39:41.000000000 +0100
@@ -1,2 +1,7 @@
[pytest]
DJANGO_SETTINGS_MODULE=tests.settings
+filterwarnings =
+ error::DeprecationWarning
+ ignore:This module and all its contents is deprecated in favour of new
moneyed.l10n.format_money\.:DeprecationWarning
+ ignore:`Money\.decimal_places_display` is deprecated and will be removed
in django-money 3\.0\.:DeprecationWarning
+ ignore:`CURRENCY_DECIMAL_PLACES_DISPLAY` is deprecated and will be removed
in django-money 3\.0\.:DeprecationWarning
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/setup.py
new/django-money-2.1.1/setup.py
--- old/django-money-1.3.1/setup.py 2021-02-04 10:32:33.000000000 +0100
+++ new/django-money-2.1.1/setup.py 2022-01-02 18:39:41.000000000 +0100
@@ -55,8 +55,10 @@
setup(
name="django-money",
version=find_version(),
- description="Adds support for using money and currency fields in django
models and forms. "
- "Uses py-moneyed as the money implementation.",
+ description=(
+ "Adds support for using money and currency fields in django models and
forms. "
+ "Uses py-moneyed as the money implementation."
+ ),
long_description=read("README.rst"),
long_description_content_type="text/x-rst",
url="https://github.com/django-money/django-money",
@@ -64,8 +66,8 @@
maintainer_email="[email protected]",
license="BSD",
packages=find_packages(include=["djmoney", "djmoney.*"]),
- install_requires=["setuptools", "Django>=1.11", "py-moneyed>=0.8,<1.0"],
- python_requires=">=3.5",
+ install_requires=["setuptools", "Django>=2.2", "py-moneyed>=1.2,<2.0"],
+ python_requires=">=3.6",
platforms=["Any"],
keywords=["django", "py-money", "money"],
classifiers=[
@@ -74,14 +76,11 @@
"License :: OSI Approved :: BSD License",
"Operating System :: OS Independent",
"Framework :: Django",
- "Framework :: Django :: 1.11",
- "Framework :: Django :: 2.1",
"Framework :: Django :: 2.2",
- "Framework :: Django :: 3.0",
"Framework :: Django :: 3.1",
+ "Framework :: Django :: 3.2",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tests/conftest.py
new/django-money-2.1.1/tests/conftest.py
--- old/django-money-1.3.1/tests/conftest.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/tests/conftest.py 2022-01-02 18:39:41.000000000
+0100
@@ -1,3 +1,5 @@
+from unittest import mock
+
import pytest
from djmoney.contrib.exchange.models import ExchangeBackend, Rate,
get_default_backend_name
@@ -10,12 +12,12 @@
return ModelWithDefaultAsInt.objects.create(money=Money(100, "USD"))
[email protected]()
[email protected]
def backend():
return ExchangeBackend.objects.create(name=get_default_backend_name(),
base_currency="USD")
[email protected]()
[email protected]
def autoconversion(backend, settings):
settings.AUTO_CONVERT_MONEY = True
Rate.objects.create(currency="EUR", value="0.88", backend=backend)
@@ -29,3 +31,9 @@
pytest_plugins = "pytester"
+
+
[email protected]_fixture
+def legacy_formatting():
+ with mock.patch("djmoney.money.IS_DECIMAL_PLACES_DISPLAY_SET", True):
+ yield
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-money-1.3.1/tests/contrib/exchange/test_model.py
new/django-money-2.1.1/tests/contrib/exchange/test_model.py
--- old/django-money-1.3.1/tests/contrib/exchange/test_model.py 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/tests/contrib/exchange/test_model.py 2022-01-02
18:39:41.000000000 +0100
@@ -46,13 +46,13 @@
@pytest.mark.parametrize("source, target", (("NOK", "ZAR"), ("ZAR", "NOK"),
("USD", "ZAR"), ("ZAR", "USD")))
@pytest.mark.usefixtures("default_openexchange_rates")
def test_unknown_currency_with_partially_exiting_currencies(source, target):
- with pytest.raises(MissingRate, match="Rate %s \\-\\> %s does not exist" %
(source, target)):
+ with pytest.raises(MissingRate, match=f"Rate {source} \\-\\> {target} does
not exist"):
get_rate(source, target)
@pytest.mark.parametrize("source, target", (("USD", "EUR"), ("SEK", "ZWL")))
def test_unknown_currency(source, target):
- with pytest.raises(MissingRate, match="Rate %s \\-\\> %s does not exist" %
(source, target)):
+ with pytest.raises(MissingRate, match=f"Rate {source} \\-\\> {target} does
not exist"):
get_rate(source, target)
@@ -106,4 +106,4 @@
"""
)
)
- result.stdout.fnmatch_lines(["US$1.00"])
+ result.stdout.fnmatch_lines(["$1.00"])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-money-1.3.1/tests/contrib/test_django_rest_framework.py
new/django-money-2.1.1/tests/contrib/test_django_rest_framework.py
--- old/django-money-1.3.1/tests/contrib/test_django_rest_framework.py
2021-02-04 10:32:33.000000000 +0100
+++ new/django-money-2.1.1/tests/contrib/test_django_rest_framework.py
2022-01-02 18:39:41.000000000 +0100
@@ -1,3 +1,4 @@
+from collections import Counter
from decimal import Decimal
import pytest
@@ -10,6 +11,7 @@
pytestmark = pytest.mark.django_db
serializers = pytest.importorskip("rest_framework.serializers")
fields = pytest.importorskip("rest_framework.fields")
+djmoney_fields =
pytest.importorskip("djmoney.contrib.django_rest_framework.fields")
class TestMoneyField:
@@ -111,12 +113,12 @@
@pytest.mark.parametrize(
"value, error",
(
- (Money(50, "EUR"), u"Ensure this value is greater than or equal to
100.00 ???."),
- (Money(1500, "EUR"), u"Ensure this value is less than or equal to
1,000.00 ???."),
+ (Money(50, "EUR"), "Ensure this value is greater than or equal to
???100.00."),
+ (Money(1500, "EUR"), "Ensure this value is less than or equal to
???1,000.00."),
(Money(40, "USD"), "Ensure this value is greater than or equal to
$50.00."),
(Money(600, "USD"), "Ensure this value is less than or equal to
$500.00."),
- (Money(400, "NOK"), "Ensure this value is greater than or equal to
500.00 Nkr."),
- (Money(950, "NOK"), "Ensure this value is less than or equal to
900.00 Nkr."),
+ (Money(400, "NOK"), "Ensure this value is greater than or equal to
NOK500.00."),
+ (Money(950, "NOK"), "Ensure this value is less than or equal to
NOK900.00."),
(Money(5, "SEK"), "Ensure this value is greater than or equal to
10."),
(Money(1600, "SEK"), "Ensure this value is less than or equal to
1500."),
),
@@ -144,3 +146,61 @@
)
assert not serializer.is_valid()
assert serializer.errors["field"][0] == error
+
+ @pytest.mark.parametrize(
+ ("data", "error_codes"),
+ [
+ pytest.param(
+ {"money": "", "money_currency": "XUA"},
+ [("money", "invalid")],
+ id="amount_as_empty_string",
+ ),
+ pytest.param(
+ {"money": None, "money_currency": "XUA"},
+ [("money", "null")],
+ id="amount_as_none",
+ ),
+ pytest.param(
+ {"money": "v", "money_currency": "XUA"},
+ [("money", "invalid")],
+ id="amount_as_invalid_decimal",
+ ),
+ pytest.param(
+ {"money": "0.01", "money_currency": "v"},
+ [("money", "invalid_currency")],
+ id="invalid_currency",
+ ),
+ pytest.param(
+ {"money_currency": "SEK"},
+ [("money", "required")],
+ id="amount_key_not_in_data",
+ ),
+ ],
+ )
+ def test_errors_on(self, data, error_codes):
+ class Serializer(serializers.Serializer):
+ money = djmoney_fields.MoneyField(max_digits=9, decimal_places=2)
+
+ serializer = Serializer(data=data)
+ with pytest.raises(serializers.ValidationError) as err:
+ serializer.is_valid(raise_exception=True)
+
+ assert Counter([(field, code) for field, codes in
err.value.get_codes().items() for code in codes]) == Counter(
+ error_codes
+ )
+
+ @pytest.mark.parametrize(
+ ("data", "expected"),
+ [
+ pytest.param({"money": "0.01", "money_currency": None},
Decimal("0.01"), id="is_none"),
+ pytest.param({"money": "0.01", "money_currency": ""},
Decimal("0.01"), id="is_empty_string"),
+ pytest.param({"money": "0.01"}, Decimal("0.01"),
id="key_not_in_data"),
+ ],
+ )
+ def test_returns_decimal_when_currency(self, data, expected):
+ class Serializer(serializers.Serializer):
+ money = djmoney_fields.MoneyField(max_digits=9, decimal_places=2)
+
+ serializer = Serializer(data=data)
+ serializer.is_valid(raise_exception=True)
+ assert serializer.validated_data["money"] == expected
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tests/migrations/helpers.py
new/django-money-2.1.1/tests/migrations/helpers.py
--- old/django-money-1.3.1/tests/migrations/helpers.py 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/tests/migrations/helpers.py 2022-01-02
18:39:41.000000000 +0100
@@ -19,7 +19,7 @@
def get_migration(name):
- return __import__("money_app.migrations.%s_%s" % (name, MIGRATION_NAME),
fromlist=["Migration"]).Migration
+ return __import__(f"money_app.migrations.{name}_{MIGRATION_NAME}",
fromlist=["Migration"]).Migration
def get_operations(migration_name):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/django-money-1.3.1/tests/migrations/test_migrations.py
new/django-money-2.1.1/tests/migrations/test_migrations.py
--- old/django-money-1.3.1/tests/migrations/test_migrations.py 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/tests/migrations/test_migrations.py 2022-01-02
18:39:41.000000000 +0100
@@ -66,8 +66,12 @@
)
tests_path = os.path.dirname(os.path.dirname(tests.__file__))
return self.run(
- "import sys; sys.path.append('{}');".format(tests_path)
- + "from tests.migrations.helpers import makemigrations;
makemigrations();"
+ f"""
+ import sys
+ sys.path.append('{tests_path}')
+ from tests.migrations.helpers import makemigrations
+ makemigrations()
+ """
)
def make_default_migration(self, field="MoneyField(max_digits=10,
decimal_places=2, null=True)"):
@@ -77,31 +81,37 @@
return self.testdir.runpython_c(
dedent(
"""
- import os
- os.environ['DJANGO_SETTINGS_MODULE'] = 'app_settings'
- from django import setup
+ import os
+ os.environ['DJANGO_SETTINGS_MODULE'] = 'app_settings'
+ from django import setup
- setup()
- %s
- """
- % content
+ setup()
+ """
)
+ + dedent(content)
)
def create_instance(self):
self.run(
"""
- from money_app.models import Model
- from djmoney.money import Money
+ from money_app.models import Model
+ from djmoney.money import Money
- Model.objects.create(field=Money(10, 'USD'))"""
+ Model.objects.create(field=Money(10, 'USD'))
+ """
)
def migrate(self):
tests_path = os.path.dirname(os.path.dirname(tests.__file__))
return self.run(
- "import sys; sys.path.append('{}');".format(tests_path)
- + "from tests.migrations.helpers import migrate; migrate();"
+ dedent(
+ f"""
+ import sys
+ sys.path.append('{tests_path}')
+ from tests.migrations.helpers import migrate
+ migrate()
+ """
+ )
)
def assert_migrate(self, output=None):
@@ -200,13 +210,13 @@
self.assert_migrate(["*Applying money_app.0002_test... OK*"])
result = self.run(
"""
- from money_app.models import Model
+ from money_app.models import Model
- instance = Model.objects.get()
- print(instance.new_field)
- """
+ instance = Model.objects.get()
+ print(instance.new_field)
+ """
)
- result.stdout.fnmatch_lines(["US$10.00"])
+ result.stdout.fnmatch_lines(["$10.00"])
def test_migrate_to_moneyfield(self):
self.make_default_migration(field="models.DecimalField(max_digits=10,
decimal_places=2, null=True)")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tests/test_admin.py
new/django-money-2.1.1/tests/test_admin.py
--- old/django-money-1.3.1/tests/test_admin.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/tests/test_admin.py 2022-01-02 18:39:41.000000000
+0100
@@ -21,6 +21,24 @@
(Money("3.33", "EUR"), "3.33 ???"), # Issue 90
),
)
+def test_display_for_field_with_legacy_formatting(legacy_formatting, settings,
value, expected):
+ settings.USE_L10N = True
+ # This locale has no definitions in py-moneyed, so it will work for
localized money representation.
+ settings.LANGUAGE_CODE = "cs"
+ settings.DECIMAL_PLACES_DISPLAY = {}
+ assert admin_utils.display_for_field(value, MONEY_FIELD, "") == expected
+
+
[email protected](
+ "value, expected",
+ (
+ (Money(10, "RUB"), "10,00\xa0RUB"), # Issue 232
+ (Money(1234), "1\xa0234,00\xa0XYZ"), # Issue 220
+ (Money(1000, "SAR"), "1\xa0000,00\xa0SAR"), # Issue 196
+ (Money(1000, "PLN"), "1\xa0000,00\xa0PLN"), # Issue 102
+ (Money("3.33", "EUR"), "3,33\xa0???"), # Issue 90
+ ),
+)
def test_display_for_field(settings, value, expected):
settings.USE_L10N = True
# This locale has no definitions in py-moneyed, so it will work for
localized money representation.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tests/test_form.py
new/django-money-2.1.1/tests/test_form.py
--- old/django-money-1.3.1/tests/test_form.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/tests/test_form.py 2022-01-02 18:39:41.000000000
+0100
@@ -131,12 +131,12 @@
@pytest.mark.parametrize(
"value, error",
(
- (Money(50, "EUR"), u"Ensure this value is greater than or equal to
100.00 ???."),
- (Money(1500, "EUR"), u"Ensure this value is less than or equal to
1,000.00 ???."),
+ (Money(50, "EUR"), "Ensure this value is greater than or equal to
???100.00."),
+ (Money(1500, "EUR"), "Ensure this value is less than or equal to
???1,000.00."),
(Money(40, "USD"), "Ensure this value is greater than or equal to
$50.00."),
(Money(600, "USD"), "Ensure this value is less than or equal to
$500.00."),
- (Money(400, "NOK"), "Ensure this value is greater than or equal to
500.00 Nkr."),
- (Money(950, "NOK"), "Ensure this value is less than or equal to
900.00 Nkr."),
+ (Money(400, "NOK"), "Ensure this value is greater than or equal to
NOK500.00."),
+ (Money(950, "NOK"), "Ensure this value is less than or equal to
NOK900.00."),
(Money(5, "SEK"), "Ensure this value is greater than or equal to
10."),
(Money(1600, "SEK"), "Ensure this value is less than or equal to
1500."),
),
@@ -171,7 +171,7 @@
def test_default_django_validator(self):
form = MoneyModelFormWithValidation(data={"balance_0": 0, "balance_1":
"GBP"})
assert not form.is_valid()
- assert form.errors == {"balance": [u"Ensure this value is greater than
or equal to GB??100.00."]}
+ assert form.errors == {"balance": ["Ensure this value is greater than
or equal to ??100.00."]}
class TestDisabledField:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tests/test_models.py
new/django-money-2.1.1/tests/test_models.py
--- old/django-money-1.3.1/tests/test_models.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/tests/test_models.py 2022-01-02 18:39:41.000000000
+0100
@@ -706,7 +706,7 @@
When current locale is changed, Money instances should be represented
correctly.
"""
with override("cs"):
- assert str(Money(10, "CZK")) == "10.00 K??"
+ assert str(Money(10, "CZK")) == "10,00??K??"
def test_properties_access():
@@ -787,3 +787,34 @@
instance = mixer.blend(ModelWithTwoMoneyFields)
assert isinstance(instance.amount1, Money)
assert isinstance(instance.amount2, Money)
+
+
[email protected](
+ ("attribute", "build_kwargs", "expected"),
+ [
+ pytest.param(
+ "default_currency",
+ {"max_digits": 9, "null": True, "default_currency": None},
+ None,
+ id="default_currency_as_none",
+ ),
+ pytest.param(
+ "default_currency",
+ {"max_digits": 9, "null": True, "default_currency": "SEK"},
+ "SEK",
+ id="default_currency_as_non_default_not_none",
+ ),
+ pytest.param(
+ "currency_max_length",
+ {"max_digits": 9, "currency_max_length": 4},
+ 4,
+ id="currency_max_length_as_non_default",
+ ),
+ ],
+)
+def test_deconstruct_includes(attribute, build_kwargs, expected):
+ instance = MoneyField(**build_kwargs)
+ __, ___, args, kwargs = instance.deconstruct()
+ new = MoneyField(*args, **kwargs)
+ assert getattr(new, attribute) == getattr(instance, attribute)
+ assert getattr(new, attribute) == expected
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tests/test_money.py
new/django-money-2.1.1/tests/test_money.py
--- old/django-money-1.3.1/tests/test_money.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/tests/test_money.py 2022-01-02 18:39:41.000000000
+0100
@@ -6,11 +6,19 @@
def test_repr():
- assert repr(Money("10.5", "USD")) == "<Money: 10.5 USD>"
+ assert repr(Money("10.5", "USD")) == "Money('10.5', 'USD')"
+
+
+def test_legacy_repr():
+ assert repr(Money("10.5", "USD", decimal_places_display=2)) ==
"Money('10.5', 'USD')"
def test_html_safe():
- assert Money("10.5", "EUR").__html__() == u"10.50\xa0???"
+ assert Money("10.5", "EUR").__html__() == "???10.50"
+
+
+def test_legacy_html_safe():
+ assert Money("10.5", "EUR", decimal_places_display=2).__html__() ==
"10.50\xa0???"
def test_html_unsafe():
@@ -35,7 +43,29 @@
10 / Money(5, "USD")
[email protected]("locale, expected", (("pl", "PL_PL"), ("pl_PL",
"pl_PL")))
[email protected](
+ "locale, expected",
+ (
+ ("pl", "PL_PL"),
+ ("pl_PL", "pl_PL"),
+ ),
+)
+def test_legacy_get_current_locale(locale, expected):
+ with override(locale):
+ assert get_current_locale(for_babel=False) == expected
+
+
[email protected](
+ "locale, expected",
+ (
+ ("pl", "pl"),
+ ("pl-pl", "pl_PL"),
+ ("sv", "sv"),
+ ("sv-se", "sv_SE"),
+ ("en-us", "en_US"),
+ ("en-gb", "en_GB"),
+ ),
+)
def test_get_current_locale(locale, expected):
with override(locale):
assert get_current_locale() == expected
@@ -123,3 +153,59 @@
for bill in bills:
total -= bill
assert total == Money(-33, "EUR")
+
+
[email protected](
+ "decimal_places_display, decimal_places",
+ [
+ [None, None],
+ [0, 0],
+ [1, 0],
+ [4, 0],
+ [0, 1],
+ [1, 1],
+ [4, 1],
+ [0, 4],
+ [1, 4],
+ [4, 4],
+ [None, 4],
+ [None, 1],
+ [None, 0],
+ [4, None],
+ [1, None],
+ [0, None],
+ ],
+)
+def test_proper_copy_of_attributes(decimal_places_display, decimal_places):
+ one = Money(1, "EUR", decimal_places_display=decimal_places_display)
+
+ assert one._decimal_places_display is decimal_places_display
+ assert one.decimal_places == 2, "default value"
+
+ two = Money(2, "EUR", decimal_places=decimal_places)
+
+ assert two._decimal_places_display is None, "default value"
+ assert two.decimal_places == decimal_places
+
+ result = Money(3, "EUR")
+ one._copy_attributes(two, result)
+
+ assert result._decimal_places_display == decimal_places_display
+ assert result.decimal_places == max(2, decimal_places) if decimal_places
is not None else 2
+
+ result = Money(0, "EUR")
+ one._copy_attributes(Money(1, "EUR", decimal_places_display=3), result)
+
+ assert result._decimal_places_display == max(3, decimal_places_display) if
decimal_places_display is not None else 3
+
+ result = Money(0, "EUR")
+ one._copy_attributes(1, result)
+
+ assert result._decimal_places_display == decimal_places_display
+ assert result.decimal_places == 2
+
+ result = Money(0, "EUR")
+ two._copy_attributes(1, result)
+
+ assert result._decimal_places_display is None
+ assert result.decimal_places == decimal_places if decimal_places else 2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tests/test_serialization.py
new/django-money-2.1.1/tests/test_serialization.py
--- old/django-money-1.3.1/tests/test_serialization.py 2021-02-04
10:32:33.000000000 +0100
+++ new/django-money-2.1.1/tests/test_serialization.py 2022-01-02
18:39:41.000000000 +0100
@@ -9,7 +9,7 @@
from djmoney.money import Money
from djmoney.serializers import Deserializer, Serializer
-from .testapp.models import ModelWithDefaultAsInt
+from .testapp.models import ModelWithDefaultAsInt, ModelWithSharedCurrency
pytestmark = pytest.mark.django_db
@@ -95,3 +95,16 @@
with patch("django.core.serializers.python._get_model", _get_model):
loaddata(fixture_file)
assert ModelWithDefaultAsInt.objects.get().money == Money(1, "USD")
+
+
+def test_serialize_currency_field(fixture_file):
+ data = """[
+ {
+ "model": "testapp.modelwithsharedcurrency",
+ "pk": 1,
+ "fields": {"first": "1.00", "second": "2.00", "currency": "USD"}
+ }
+]"""
+ fixture_file.write(data)
+ loaddata(fixture_file)
+ assert ModelWithSharedCurrency.objects.get().first == Money(1, "USD")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tests/test_tags.py
new/django-money-2.1.1/tests/test_tags.py
--- old/django-money-1.3.1/tests/test_tags.py 2021-02-04 10:32:33.000000000
+0100
+++ new/django-money-2.1.1/tests/test_tags.py 2022-01-02 18:39:41.000000000
+0100
@@ -84,6 +84,49 @@
),
),
)
+def test_tag_with_legacy_formatting(legacy_formatting, string, result,
context):
+ assert_template(string, result, context)
+
+
[email protected](
+ "string, result, context",
+ (
+ ('{% load djmoney %}{% money_localize "2.5" "PLN" as NEW_M
%}{{NEW_M}}', "2,50\xa0z??", {}),
+ ('{% load djmoney %}{% money_localize "2.5" "PLN" %}', "2,50\xa0z??",
{}),
+ ("{% load djmoney %}{% money_localize amount currency %}",
"2,60\xa0z??", {"amount": 2.6, "currency": "PLN"}),
+ ("{% load djmoney %}{% money_localize money as NEW_M %}{{NEW_M}}",
"2,30\xa0z??", {"money": Money(2.3, "PLN")}),
+ (
+ "{% load djmoney %}{% money_localize money off as NEW_M
%}{{NEW_M}}",
+ "2,30\xa0z??",
+ {"money": Money(2.3, "PLN")},
+ ),
+ (
+ "{% load djmoney %}{% money_localize money off as NEW_M
%}{{NEW_M}}",
+ "0,00\xa0z??",
+ {"money": Money(0, "PLN")},
+ ),
+ (
+ # with a tag template "money_localize"
+ "{% load djmoney %}{% money_localize money %}",
+ "2,30\xa0z??",
+ {"money": Money(2.3, "PLN")},
+ ),
+ (
+ # without a tag template "money_localize"
+ "{{ money }}",
+ "2,30\xa0z??",
+ {"money": Money(2.3, "PLN")},
+ ),
+ ("{% load djmoney %}{% money_localize money off %}", "2,30\xa0z??",
{"money": Money(2.3, "PLN")}),
+ ("{% load djmoney %}{% money_localize money on %}", "2,30\xa0z??",
{"money": Money(2.3, "PLN")}),
+ (
+ # in django 2.0 we fail inside the for loop
+ '{% load djmoney %}{% for i in "xxx" %}{% money_localize money %}
{% endfor %}',
+ "2,30\xa0z?? 2,30\xa0z?? 2,30\xa0z?? ",
+ {"money": Money(2.3, "PLN"), "test": "test"},
+ ),
+ ),
+)
def test_tag(string, result, context):
assert_template(string, result, context)
@@ -94,16 +137,16 @@
(
# money_localize has a default setting USE_L10N = True
"{% load djmoney %}{% money_localize money %}",
- "2,30 z??",
+ "2,30\xa0z??",
{"money": Money(2.3, "PLN")},
),
(
# without a tag template "money_localize"
"{{ money }}",
- "2.30 z??",
+ "2,30\xa0z??",
{"money": Money(2.3, "PLN")},
),
- ("{% load djmoney %}{% money_localize money on %}", "2,30 z??",
{"money": Money(2.3, "PLN")}),
+ ("{% load djmoney %}{% money_localize money on %}", "2,30\xa0z??",
{"money": Money(2.3, "PLN")}),
),
)
def test_l10n_off(settings, string, result, context):
@@ -114,4 +157,4 @@
def test_forced_l10n():
mp = Money(2.3, "PLN")
mp.use_l10n = True
- assert_template("{{ money }}", "2,30 z??", {"money": mp})
+ assert_template("{{ money }}", "2,30\xa0z??", {"money": mp})
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/django-money-1.3.1/tox.ini
new/django-money-2.1.1/tox.ini
--- old/django-money-1.3.1/tox.ini 2021-02-04 10:32:33.000000000 +0100
+++ new/django-money-2.1.1/tox.ini 2022-01-02 18:39:41.000000000 +0100
@@ -1,11 +1,9 @@
[tox]
envlist =
- django_master-py{39,38,37,36,py3}
+ django_main-py{39,38,37,36,py3}
+ django32-py{39,38,37,36,py3}
django31-py{39,38,37,36,py3}
- django30-py{39,38,37,36,py3}
django22-py{39,38,37,36,py3}
- django21-py{37,36,35,py3}
- django111-py{36,35,py3}
lint
docs
skipsdist = true
@@ -17,51 +15,37 @@
[testenv]
deps =
.[test,exchange]
- django111: {[django]1.11.x}
- django21: {[django]2.1.x}
django22: {[django]2.2.x}
- django30: {[django]3.0.x}
django31: {[django]3.1.x}
- django_master: {[django]master}
-commands = py.test --ds=tests.settings_reversion --cov=./djmoney {posargs} -W
error::DeprecationWarning
+ django32: {[django]3.2.x}
+ django_main: {[django]main}
+commands = py.test --ds=tests.settings_reversion --cov=./djmoney {posargs}
usedevelop = false
-[testenv:django_master-py{39,38,37,36,py3}]
-commands = py.test --ds=tests.settings --cov=./djmoney {posargs} -W
error::DeprecationWarning
+[testenv:django_main-py{39,38,py3}]
+commands = py.test --ds=tests.settings --cov=./djmoney {posargs}
[testenv:lint]
deps =
- flake8
- isort
- black
+ pre-commit
commands =
- flake8 {toxinidir}/djmoney {toxinidir}/tests
- isort -c {toxinidir}/djmoney {toxinidir}/tests
- black -l 120 --check --diff {toxinidir}/djmoney {toxinidir}/tests setup.py
+ pre-commit run --all-files
[django]
-1.11.x =
- Django>=1.11.0,<2.0.0
- django-reversion>=2.0.8,<3.0.8
- djangorestframework>=3.6.2
-2.1.x =
- Django>=2.1,<2.2
- django-reversion>=2.0.8
- djangorestframework>=3.7.3
2.2.x =
Django>=2.2,<2.3
django-reversion>=2.0.8
djangorestframework>=3.7.3
-3.0.x =
- Django>=3.0,<3.1
- django-reversion>=2.0.8
- djangorestframework>=3.7.3
3.1.x =
Django>=3.1,<3.2
django-reversion>=3.0.8
djangorestframework>=3.12.0
-master =
- https://github.com/django/django/tarball/master
+3.2.x =
+ Django>=3.2,<3.3
+ django-reversion>=3.0.8
+ djangorestframework>=3.12.0
+main =
+ https://github.com/django/django/tarball/main
djangorestframework>=3.12.0
[testenv:no_rest_framework]
@@ -71,7 +55,7 @@
django-reversion>=3.0.8
[testenv:docs]
-basepython = python3.6
+allowlist_externals = make
changedir = docs
deps =
sphinx
++++++ merged_pr_657.patch ++++++
>From b140c16ca8f9ed0227f5295878c3f6b346a8472c Mon Sep 17 00:00:00 2001
From: David Szotten <[email protected]>
Date: Wed, 19 Jan 2022 17:53:07 +0000
Subject: [PATCH 1/5] failing test to expose issue
---
tests/test_models.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tests/test_models.py b/tests/test_models.py
index fb5b55cc..0ae6ba4e 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -5,6 +5,7 @@
"""
import datetime
from copy import copy
+from decimal import Decimal
from django import VERSION
from django.core.exceptions import ValidationError
@@ -373,6 +374,12 @@ def test_fails_with_null_currency(self):
assert str(exc.value) == "Missing currency value"
assert not ModelWithNullableCurrency.objects.exists()
+ def test_fails_with_null_currency_decimal(self):
+ with pytest.raises(ValueError) as exc:
+ ModelWithNullableCurrency.objects.create(money=Decimal(10))
+ assert str(exc.value) == "Missing currency value"
+ assert not ModelWithNullableCurrency.objects.exists()
+
def test_fails_with_nullable_but_no_default(self):
with pytest.raises(IntegrityError) as exc:
ModelWithTwoMoneyFields.objects.create()
>From 2ccaadc4e1d3a7ca06ba96ee683fb9057daa8d94 Mon Sep 17 00:00:00 2001
From: David Szotten <[email protected]>
Date: Wed, 19 Jan 2022 17:54:30 +0000
Subject: [PATCH 2/5] suggested better fix for
https://github.com/django-money/django-money/pull/427/
TODO: is the currency field guaranteed to appear before the amount (and main)
field? yes because of the creation_counters?
---
djmoney/models/fields.py | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/djmoney/models/fields.py b/djmoney/models/fields.py
index 8eb710ba..3bfd7dda 100644
--- a/djmoney/models/fields.py
+++ b/djmoney/models/fields.py
@@ -104,7 +104,12 @@ def __get__(self, obj, type=None):
return data[self.field.name]
def __set__(self, obj, value): # noqa
- if value is not None and self.field._currency_field.null and not
isinstance(value, MONEY_CLASSES + (Decimal,)):
+ if (
+ value is not None
+ and self.field._currency_field.null
+ and not isinstance(value, MONEY_CLASSES)
+ and not obj.__dict__[self.currency_field_name]
+ ):
# For nullable fields we need either both NULL amount and currency
or both NOT NULL
raise ValueError("Missing currency value")
if isinstance(value, BaseExpression):
>From 952ac5a75b43a632febe733d0aa1a5a716b7735c Mon Sep 17 00:00:00 2001
From: David Szotten <[email protected]>
Date: Wed, 19 Jan 2022 22:09:06 +0000
Subject: [PATCH 3/5] fix django error message change
fix for
https://github.com/django/django/commit/08d8bccbf1b0764a0de68325569ee47da256e206
---
tests/test_models.py | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tests/test_models.py b/tests/test_models.py
index 0ae6ba4e..53def7cb 100644
--- a/tests/test_models.py
+++ b/tests/test_models.py
@@ -719,7 +719,9 @@ def test_override_decorator():
def test_properties_access():
with pytest.raises(TypeError) as exc:
ModelWithVanillaMoneyField(money=Money(1, "USD"), bla=1)
- if VERSION[:2] > (2, 1):
+ if VERSION[:2] > (4, 0):
+ assert str(exc.value) == "ModelWithVanillaMoneyField() got unexpected
keyword arguments: 'bla'"
+ elif VERSION[:2] > (2, 1):
assert str(exc.value) == "ModelWithVanillaMoneyField() got an
unexpected keyword argument 'bla'"
else:
assert str(exc.value) == "'bla' is an invalid keyword argument for
this function"
>From 620af5355a22ca1da0cb43c8e5787c3e8b76f995 Mon Sep 17 00:00:00 2001
From: David Szotten <[email protected]>
Date: Thu, 20 Jan 2022 08:59:37 +0000
Subject: [PATCH 4/5] better match the signature of input()
for compat with django 0ab58c120939093fea90822f376e1866fc714d1f
---
tests/migrations/helpers.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tests/migrations/helpers.py b/tests/migrations/helpers.py
index f38067fe..cbf2c7fe 100644
--- a/tests/migrations/helpers.py
+++ b/tests/migrations/helpers.py
@@ -12,7 +12,7 @@ def makemigrations():
from django.db.migrations import questioner
# We should answer yes for all migrations questioner questions
- questioner.input = lambda x: "y"
+ questioner.input = lambda prompt=None: "y"
os.system("find . -name \\*.pyc -delete")
call_command("makemigrations", "money_app", name=MIGRATION_NAME)
>From faf4da5f96193fc1a5e0b2b838f2a13189975abf Mon Sep 17 00:00:00 2001
From: David Szotten <[email protected]>
Date: Thu, 27 Jan 2022 17:47:01 +0000
Subject: [PATCH 5/5] changelog
---
docs/changes.rst | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/docs/changes.rst b/docs/changes.rst
index 1968af75..5eab8fd1 100644
--- a/docs/changes.rst
+++ b/docs/changes.rst
@@ -1,6 +1,14 @@
Changelog
=========
+`Unreleased`_ - TBA
+-------------------
+
+**Fixed**
+
+- Improve the internal check for whether a currency is provided `#657`_
(`davidszotten`_)
+- Fix test suite for django main branch `#657`_ (`davidszotten`_)
+
`2.1.1`_ - 2022-01-02
---------------------
@@ -709,8 +717,7 @@ wrapping with ``money_manager``.
- Initial public release
-# .. _Unreleased:
https:///github.com/django-money/django-money/compare/2.1.1...HEAD
-
+.. _Unreleased:
https:///github.com/django-money/django-money/compare/2.1.1...HEAD
.. _2.1.1: https:///github.com/django-money/django-money/compare/2.1...2.1.1
.. _2.1: https:///github.com/django-money/django-money/compare/2.0.3...2.1
.. _2.0.3: https://github.com/django-money/django-money/compare/2.0.2...2.0.3
@@ -773,6 +780,7 @@ wrapping with ``money_manager``.
.. _0.3: https://github.com/django-money/django-money/compare/0.2...0.3
.. _0.2:
https://github.com/django-money/django-money/compare/0.2...a6d90348085332a393abb40b86b5dd9505489b04
+.. _#657: https://github.com/django-money/django-money/issues/657
.. _#648: https://github.com/django-money/django-money/issues/648
.. _#646: https://github.com/django-money/django-money/issues/646
.. _#637: https://github.com/django-money/django-money/issues/637
@@ -966,3 +974,4 @@ wrapping with ``money_manager``.
.. _washeck: https://github.com/washeck
.. _fara: https://github.com/fara
.. _wearebasti: https://github.com/wearebasti
+.. _davidszotten: https://github.com/davidszotten
++++++ pr_638.patch ++++++
++++ 780 lines (skipped)