Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-dirty-equals for openSUSE:Factory checked in at 2022-11-14 14:28:59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-dirty-equals (Old) and /work/SRC/openSUSE:Factory/.python-dirty-equals.new.1597 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-dirty-equals" Mon Nov 14 14:28:59 2022 rev:3 rq:1035577 version:0.5.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-dirty-equals/python-dirty-equals.changes 2022-09-01 22:11:54.352364720 +0200 +++ /work/SRC/openSUSE:Factory/.python-dirty-equals.new.1597/python-dirty-equals.changes 2022-11-14 14:29:10.507022854 +0100 @@ -1,0 +2,10 @@ +Thu Nov 10 15:18:24 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +-Update to version 0.5.0 + *Document how the dirty __eq__ is called by @Marco-Kaulea in #41 + *Make IsNow relative to current moment of time by @hyzyla in #40 + *correct version in pyproject.toml, #46 + *feat Add IsIP by @osintalex in #43 + *Remove Poetry and transition to hatchling, #49 + +------------------------------------------------------------------- Old: ---- dirty-equals-0.4.tar.gz New: ---- dirty-equals-0.5.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-dirty-equals.spec ++++++ --- /var/tmp/diff_new_pack.D3hD8s/_old 2022-11-14 14:29:11.679028279 +0100 +++ /var/tmp/diff_new_pack.D3hD8s/_new 2022-11-14 14:29:11.683028297 +0100 @@ -17,13 +17,14 @@ Name: python-dirty-equals -Version: 0.4 +Version: 0.5.0 Release: 0 Summary: Doing dirty (but useful) things with equals License: MIT URL: https://dirty-equals.helpmanual.io Source: https://github.com/samuelcolvin/dirty-equals/archive/refs/tags/v%{version}.tar.gz#/dirty-equals-%{version}.tar.gz BuildRequires: %{python_module base >= 3.7} +BuildRequires: %{python_module hatchling} BuildRequires: %{python_module pip} BuildRequires: %{python_module poetry-core} BuildRequires: %{python_module pytest-mock} ++++++ dirty-equals-0.4.tar.gz -> dirty-equals-0.5.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/.github/workflows/ci.yml new/dirty-equals-0.5.0/.github/workflows/ci.yml --- old/dirty-equals-0.4/.github/workflows/ci.yml 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/.github/workflows/ci.yml 2022-08-30 20:44:09.000000000 +0200 @@ -11,12 +11,22 @@ jobs: test: - name: test py-${{ matrix.python-version }} on ${{ matrix.os }} + name: test ${{ matrix.python-version }} on ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu, macos] - python-version: ['3.7', '3.8', '3.9', '3.10', 'pypy-3.7', 'pypy-3.8', 'pypy-3.9'] + python-version: ['3.7', '3.8', '3.9', '3.10'] + # test 3.11-dev and pypy on ubuntu only to speed up CI, no reason why macos X pypy should fail separately + include: + - os: 'ubuntu' + python-version: '3.11-dev' + - os: 'ubuntu' + python-version: 'pypy-3.7' + - os: 'ubuntu' + python-version: 'pypy-3.8' + - os: 'ubuntu' + python-version: 'pypy-3.9' runs-on: ${{ matrix.os }}-latest @@ -25,30 +35,27 @@ OS: ${{ matrix.os }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: set up python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: cache with: path: ${{ env.pythonLocation }} - key: ${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-${{ hashFiles('tests/requirements.txt') }} + key: ${{ runner.os }}-${{ env.pythonLocation }}-${{ hashFiles('pyproject.toml') }}-${{ hashFiles('requirements/tests.txt') }} - - run: pip install -r tests/requirements.txt -# if: steps.cache.outputs.cache-hit != 'true' # breaks pypy tests - - - run: poetry install -# if: steps.cache.outputs.cache-hit != 'true' # breaks pypy tests + - run: pip install -r requirements/tests.txt -r requirements/pyproject.txt + if: steps.cache.outputs.cache-hit != 'true' - run: make test - run: coverage xml - - uses: codecov/codecov-action@v2.1.0 + - uses: codecov/codecov-action@v3 with: file: ./coverage.xml env_vars: PYTHON,OS @@ -57,36 +64,37 @@ runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v4 with: python-version: '3.10' - - uses: actions/cache@v2 + - uses: actions/cache@v3 id: cache with: path: ${{ env.pythonLocation }} - key: ${{ hashFiles('tests/requirements-linting.txt') }} + key: ${{ env.pythonLocation }}-${{ hashFiles('requirements/linting.txt') }}-${{ hashFiles('pyproject.toml') }} - - run: pip install -r tests/requirements-linting.txt + - run: pip install -r requirements/linting.txt if: steps.cache.outputs.cache-hit != 'true' - - run: make lint - - run: make mypy + - uses: pre-commit/action@v3.0.0 + with: + extra_args: --all-files docs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: set up python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.10' - name: install - run: pip install -r docs/requirements.txt + run: pip install -r requirements/docs.txt - name: install mkdocs-material-insiders if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') @@ -98,7 +106,7 @@ run: mkdocs build --strict - name: store docs site - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: docs path: site @@ -112,30 +120,42 @@ runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: set up python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: '3.9' - name: get docs - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v3 with: name: docs path: site - - name: set version - run: VERSION_PATH=dirty_equals python <(curl -Ls https://bit.ly/set__version__) + - name: install + run: pip install -U twine build packaging + + - name: check version + id: check-version + run: python <(curl -Ls https://gist.githubusercontent.com/samuelcolvin/4e1ad439c5489e8d6478cdee3eb952ef/raw/check_version.py) + env: + VERSION_PATH: 'dirty_equals/version.py' + + - name: build + run: python -m build - - run: pip install poetry==1.2.0a2 poetry-version-plugin + - run: twine check dist/* - - run: poetry publish --build + - name: upload to pypi + run: twine upload dist/* env: - POETRY_PYPI_TOKEN_PYPI: ${{ secrets.pypi_token }} + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.pypi_token }} - name: publish docs - uses: JamesIves/github-pages-deploy-action@v4.2.5 + uses: JamesIves/github-pages-deploy-action@v4 + if: '!fromJSON(steps.check-version.outputs.IS_PRERELEASE)' with: branch: gh-pages folder: site diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/.pre-commit-config.yaml new/dirty-equals-0.5.0/.pre-commit-config.yaml --- old/dirty-equals-0.4/.pre-commit-config.yaml 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/.pre-commit-config.yaml 2022-08-30 20:44:09.000000000 +0200 @@ -4,7 +4,10 @@ hooks: - id: check-yaml args: ['--unsafe'] + - id: check-toml - id: end-of-file-fixer + - id: trailing-whitespace + - id: check-added-large-files - repo: local hooks: @@ -13,8 +16,10 @@ entry: make lint types: [python] language: system + pass_filenames: false - id: mypy name: Mypy entry: make mypy types: [python] language: system + pass_filenames: false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/Makefile new/dirty-equals-0.5.0/Makefile --- old/dirty-equals-0.4/Makefile 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/Makefile 2022-08-30 20:44:09.000000000 +0200 @@ -4,10 +4,7 @@ .PHONY: install install: - pip install -r tests/requirements.txt - pip install -r tests/requirements-linting.txt - pip install -r docs/requirements.txt - poetry install + pip install -r requirements/all.txt pre-commit install .PHONY: format diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/README.md new/dirty-equals-0.5.0/README.md --- old/dirty-equals-0.4/README.md 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/README.md 2022-08-30 20:44:09.000000000 +0200 @@ -74,17 +74,17 @@ *dirty-equals* can do so much more than that, for example: -* [`IsPartialDict`](https://dirty-equals.helpmanual.io/types/dict/#dirty_equals.IsPartialDict) +* [`IsPartialDict`](https://dirty-equals.helpmanual.io/types/dict/#dirty_equals.IsPartialDict) lets you compare a subset of a dictionary -* [`IsStrictDict`](https://dirty-equals.helpmanual.io/types/dict/#dirty_equals.IsStrictDict) +* [`IsStrictDict`](https://dirty-equals.helpmanual.io/types/dict/#dirty_equals.IsStrictDict) lets you confirm order in a dictionary -* [`IsList`](https://dirty-equals.helpmanual.io/types/sequence/#dirty_equals.IsList) and +* [`IsList`](https://dirty-equals.helpmanual.io/types/sequence/#dirty_equals.IsList) and [`IsTuple`](https://dirty-equals.helpmanual.io/types/sequence/#dirty_equals.IsTuple) lets you compare partial lists and tuples, with or without order constraints * nesting any of these types inside any others -* [`IsInstance`](https://dirty-equals.helpmanual.io/types/other/#dirty_equals.IsInstance) +* [`IsInstance`](https://dirty-equals.helpmanual.io/types/other/#dirty_equals.IsInstance) lets you simply confirm the type of an object -* You can even use [boolean operators](https://dirty-equals.helpmanual.io/usage/#boolean-logic) +* You can even use [boolean operators](https://dirty-equals.helpmanual.io/usage/#boolean-logic) `|` and `&` to combine multiple conditions * and much more... diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/dirty_equals/__init__.py new/dirty-equals-0.5.0/dirty_equals/__init__.py --- old/dirty-equals-0.4/dirty_equals/__init__.py 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/dirty_equals/__init__.py 2022-08-30 20:44:09.000000000 +0200 @@ -18,9 +18,10 @@ IsPositiveFloat, IsPositiveInt, ) -from ._other import FunctionCheck, IsJson, IsUUID +from ._other import FunctionCheck, IsIP, IsJson, IsUUID from ._sequence import Contains, HasLen, IsList, IsListOrTuple, IsTuple from ._strings import IsAnyStr, IsBytes, IsStr +from .version import VERSION __all__ = ( # base @@ -69,6 +70,7 @@ 'FunctionCheck', 'IsJson', 'IsUUID', + 'IsIP', # strings 'IsStr', 'IsBytes', @@ -77,4 +79,4 @@ '__version__', ) -__version__ = '0.0.dev0' +__version__ = VERSION diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/dirty_equals/_datetime.py new/dirty-equals-0.5.0/dirty_equals/_datetime.py --- old/dirty-equals-0.4/dirty_equals/_datetime.py 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/dirty_equals/_datetime.py 2022-08-30 20:44:09.000000000 +0200 @@ -163,13 +163,12 @@ tz = pytz.timezone(tz) - if tz is not None: - now = datetime.utcnow().replace(tzinfo=timezone.utc).astimezone(tz) - else: - now = datetime.now() + self.tz = tz + + approx = self._get_now() super().__init__( - approx=now, + approx=approx, delta=delta, unix_number=unix_number, iso_string=iso_string, @@ -179,6 +178,20 @@ if tz is not None: self._repr_kwargs['tz'] = tz + def _get_now(self) -> datetime: + if self.tz is None: + return datetime.now() + else: + return datetime.utcnow().replace(tzinfo=timezone.utc).astimezone(self.tz) + + def prepare(self, other: Any) -> datetime: + + # update approx for every comparing, to check if other value is dirty equal + # to current moment of time + self.approx = self._get_now() + + return super().prepare(other) + class IsDate(IsNumeric[date]): """ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/dirty_equals/_other.py new/dirty-equals-0.5.0/dirty_equals/_other.py --- old/dirty-equals-0.4/dirty_equals/_other.py 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/dirty_equals/_other.py 2022-08-30 20:44:09.000000000 +0200 @@ -1,9 +1,10 @@ import json -from typing import Any, Callable, TypeVar, overload +from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network, ip_network +from typing import Any, Callable, Optional, TypeVar, Union, overload from uuid import UUID from ._base import DirtyEquals -from ._utils import plain_repr +from ._utils import Omit, plain_repr try: from typing import Literal @@ -145,3 +146,60 @@ def equals(self, other: Any) -> bool: return self.func(other) + + +IP = TypeVar('IP', IPv4Address, IPv4Network, IPv6Address, IPv6Network, Union[str, int, bytes]) + + +class IsIP(DirtyEquals[IP]): + """ + A class that checks if a value is a valid IP address, optionally checking IP version, netmask. + """ + + def __init__(self, *, version: Literal[None, 4, 6] = None, netmask: Optional[str] = None): + """ + Args: + version: The version of the IP to check, if omitted, versions 4 and 6 are both accepted. + netmask: The netmask of the IP to check, if omitted, any netmask is accepted. Requires version. + + ```py title="IsIP" + from ipaddress import IPv4Address, IPv6Address, IPv4Network + from dirty_equals import IsIP + + assert '179.27.154.96' == IsIP + assert '179.27.154.96' == IsIP(version=4) + assert '2001:0db8:0a0b:12f0:0000:0000:0000:0001' == IsIP(version=6) + assert IPv4Address('127.0.0.1') == IsIP + assert IPv4Network('43.48.0.0/12') == IsIP + assert IPv6Address('::eeff:ae3f:d473') == IsIP + assert '54.43.53.219/10' == IsIP(version=4, netmask='255.192.0.0') + assert '54.43.53.219/10' == IsIP(version=4, netmask=4290772992) + assert '::ffff:aebf:d473/12' == IsIP(version=6, netmask='fff0::') + assert 3232235521 == IsIP + ``` + """ + self.version = version + if netmask and not self.version: + raise TypeError('To check the netmask you must specify the IP version') + self.netmask = netmask + super().__init__(version=version or Omit, netmask=netmask or Omit) + + def equals(self, other: Any) -> bool: + + if isinstance(other, (IPv4Network, IPv6Network)): + ip = other + elif isinstance(other, (str, bytes, int, IPv4Address, IPv6Address)): + ip = ip_network(other, strict=False) + else: + return False + + if self.version: + if self.netmask: + version_check = self.version == ip.version + address_format = {4: IPv4Address, 6: IPv6Address}[self.version] + netmask_check = int(address_format(self.netmask)) == int(ip.netmask) + return version_check and netmask_check + elif self.version != ip.version: + return False + + return True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/dirty_equals/version.py new/dirty-equals-0.5.0/dirty_equals/version.py --- old/dirty-equals-0.4/dirty_equals/version.py 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/dirty_equals/version.py 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1 @@ +VERSION = '0.5.0' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/docs/index.md new/dirty-equals-0.5.0/docs/index.md --- old/dirty-equals-0.4/docs/index.md 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/docs/index.md 2022-08-30 20:44:09.000000000 +0200 @@ -44,7 +44,7 @@ ``` 1. This `assert` will pass since `1` is indeed positive, so the result of `1 == IsPositive` is `True`. -2. This will fail (raise a `AssertionError`) since `-2` is not positive, +2. This will fail (raise a `AssertionError`) since `-2` is not positive, so the result of `-2 == IsPositive` is `False`. **Not that interesting yet!**, but consider the following unit test code using **dirty-equals**: @@ -53,7 +53,7 @@ title="More Powerful Usage" from dirty_equals import IsJson, IsNow, IsPositiveInt, IsStr -def test_user_endpoint(client: 'HttpClient', db_conn: 'Database'): +def test_user_endpoint(client: 'HttpClient', db_conn: 'Database'): client.pust('/users/create/', data=...) user_data = db_conn.fetchrow('select * from users') @@ -68,21 +68,21 @@ 1. We don't actually care what the `id` is, just that it's present, it's an `int` and it's positive. 2. We can use a normal key and value here since we know exactly what value `username` should have before we test it. -3. `avatar_file` is a string, but we don't know all of the string before the `assert`, +3. `avatar_file` is a string, but we don't know all of the string before the `assert`, just the format (regex) it should match. 4. `settings_json` is a `JSON` string, but it's simpler and more robust to confirm it represents a particular python object rather than compare strings. 5. `created_at` is a `datetime`, although we don't know (or care) about its exact value; since the user was just created we know it must be close to now. `delta` is optional, it defaults to 2 seconds. -Without **dirty-equals**, you'd have to compare individual fields and/or modify some fields before comparison +Without **dirty-equals**, you'd have to compare individual fields and/or modify some fields before comparison - the test would not be declarative or as clear. **dirty-equals** can do so much more than that, for example: * [`IsPartialDict`][dirty_equals.IsPartialDict] lets you compare a subset of a dictionary * [`IsStrictDict`][dirty_equals.IsStrictDict] lets you confirm order in a dictionary -* [`IsList`][dirty_equals.IsList] and [`IsTuple`][dirty_equals.IsTuple] lets you compare partial lists and tuples, +* [`IsList`][dirty_equals.IsList] and [`IsTuple`][dirty_equals.IsTuple] lets you compare partial lists and tuples, with or without order constraints * nesting any of these types inside any others * [`IsInstance`][dirty_equals.IsInstance] lets you simply confirm the type of an object diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/docs/internals.md new/dirty-equals-0.5.0/docs/internals.md --- old/dirty-equals-0.4/docs/internals.md 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/docs/internals.md 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,20 @@ +# Internals +## How the magic of `DirtyEquals.__eq__` works? +When you call `x == y`, Python first calls `x.__eq__(y)`. This would not help us +much, because we would have to keep an eye on order of the arguments when +comparing to `DirtyEquals` objects. But that's where were another feature of +Python comes in. + +When `x.__eq__(y)` returns the `NotImplemented` object, then Python will try to +call `y.__eq__(x)`. Objects in the standard library return that value when they +don't know how to compare themselves to objects of `type(y)` (Without checking +the C source I can't be certain if this assumption holds for all classes, but it +works for all the basic ones). +In [`pathlib.PurePath`](https://github.com/python/cpython/blob/aebbd7579a421208f48dd6884b67dbd3278b71ad/Lib/pathlib.py#L751) +you can see an example how that is implemented in Python. + +> By default, object implements `__eq__()` by using `is`, +> returning `NotImplemented` in the case of a false comparison: +> `True if x is y else NotImplemented`. + +See the Python documentation for more information ([`object.__eq__`](https://docs.python.org/3/reference/datamodel.html#object.__eq__)). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/docs/plugins.py new/dirty-equals-0.5.0/docs/plugins.py --- old/dirty-equals-0.4/docs/plugins.py 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/docs/plugins.py 2022-08-30 20:44:09.000000000 +0200 @@ -22,11 +22,13 @@ """ Run the examples tests. """ - if not pytest: + try: + run_pytest = getattr('pytest', 'main') + except AttributeError: logger.info('pytest not installed, skipping examples tests') else: logger.info('running examples tests...') - return_code = pytest.main(['-q', '-p', 'no:sugar', 'tests/test_docs.py']) + return_code = run_pytest(['-q', '-p', 'no:sugar', 'tests/test_docs.py']) if return_code != 0: logger.warning('examples tests failed') @@ -38,7 +40,7 @@ def remove_files(files: Files) -> Files: to_remove = [] for file in files: - if file.src_path in {'plugins.py', 'requirements.txt'}: + if file.src_path in {'plugins.py'}: to_remove.append(file) elif file.src_path.startswith('__pycache__/'): to_remove.append(file) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/docs/requirements.txt new/dirty-equals-0.5.0/docs/requirements.txt --- old/dirty-equals-0.4/docs/requirements.txt 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/docs/requirements.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,7 +0,0 @@ -black==22.3.0 -griffe==0.17.0 -mkdocs==1.3.0 -mkdocs-autorefs==0.4.1 -mkdocs-material==8.2.9 -mkdocs-simple-hooks==0.1.5 -mkdocstrings[python]==0.18.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/docs/types/custom.md new/dirty-equals-0.5.0/docs/types/custom.md --- old/dirty-equals-0.4/docs/types/custom.md 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/docs/types/custom.md 2022-08-30 20:44:09.000000000 +0200 @@ -27,12 +27,12 @@ assert 3 == IsEven | IsOneOf(3) ``` -There are a few advantages of inheriting from [`DirtyEquals`][dirty_equals.DirtyEquals] compared to just +There are a few advantages of inheriting from [`DirtyEquals`][dirty_equals.DirtyEquals] compared to just implementing your own class with an `__eq__` method: 1. `TypeError` and `ValueError` in `equals` are caught and result in a not-equals result. 2. A useful `__repr__` is generated, and modified if the `==` operation returns `True`, see [pytest compatibility](../usage.md#__repr__-and-pytest-compatibility) 3. [boolean logic](../usage.md#boolean-logic) works out of the box -4. [Uninitialised usage](../usage.md#initialised-vs-class-comparison) +4. [Uninitialised usage](../usage.md#initialised-vs-class-comparison) (`IsEven` rather than `IsEven()`) works out of the box diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/docs/types/datetime.md new/dirty-equals-0.5.0/docs/types/datetime.md --- old/dirty-equals-0.4/docs/types/datetime.md 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/docs/types/datetime.md 2022-08-30 20:44:09.000000000 +0200 @@ -11,12 +11,12 @@ * `enforce_tz=True` (the default): * if the datetime wrapped by `IsDatetime` is timezone naive, the compared value must also be timezone naive. - * if the datetime wrapped by `IsDatetime` has a timezone, the compared value must have a + * if the datetime wrapped by `IsDatetime` has a timezone, the compared value must have a timezone with the same offset. * `enforce_tz=False`: - * if the datetime wrapped by `IsDatetime` is timezone naive, the compared value can either be naive or have a + * if the datetime wrapped by `IsDatetime` is timezone naive, the compared value can either be naive or have a timezone all that matters is the datetime values match. - * if the datetime wrapped by `IsDatetime` has a timezone, the compared value needs to represent the same point in + * if the datetime wrapped by `IsDatetime` has a timezone, the compared value needs to represent the same point in time - either way it must have a timezone. Example diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/docs/types/other.md new/dirty-equals-0.5.0/docs/types/other.md --- old/dirty-equals-0.4/docs/types/other.md 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/docs/types/other.md 2022-08-30 20:44:09.000000000 +0200 @@ -11,3 +11,5 @@ ::: dirty_equals.AnyThing ::: dirty_equals.IsOneOf + +::: dirty_equals.IsIP diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/docs/usage.md new/dirty-equals-0.5.0/docs/usage.md --- old/dirty-equals-0.4/docs/usage.md 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/docs/usage.md 2022-08-30 20:44:09.000000000 +0200 @@ -1,7 +1,7 @@ ## Boolean Logic -*dirty-equals* types can be combined based on either `&` -(and, all checks must be `True` for the combined check to be `True`) or `|` +*dirty-equals* types can be combined based on either `&` +(and, all checks must be `True` for the combined check to be `True`) or `|` (or, any check can be `True` for the combined check to be `True`). Types can also be inverted using the `~` operator, this is equivalent to using `!=` instead of `==`. @@ -72,7 +72,7 @@ assert repr(v) == '42' ``` -This black magic is designed to make the output of pytest when asserts on large objects fail as simple as +This black magic is designed to make the output of pytest when asserts on large objects fail as simple as possible to read. Consider the following unit test: @@ -100,7 +100,7 @@ } ``` -1. For simplicity we've hardcoded `id` here, but in a test it could be any positive int, +1. For simplicity we've hardcoded `id` here, but in a test it could be any positive int, hence why we need `IsPositiveInt()` Here's an except from the output of `pytest -vv` show the error details: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/mkdocs.yml new/dirty-equals-0.5.0/mkdocs.yml --- old/dirty-equals-0.4/mkdocs.yml 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/mkdocs.yml 2022-08-30 20:44:09.000000000 +0200 @@ -44,6 +44,7 @@ - types/boolean.md - types/other.md - types/custom.md + - Internals: internals.md markdown_extensions: - toc: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/poetry.lock new/dirty-equals-0.5.0/poetry.lock --- old/dirty-equals-0.4/poetry.lock 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/poetry.lock 1970-01-01 01:00:00.000000000 +0100 @@ -1,30 +0,0 @@ -[[package]] -name = "pytz" -version = "2022.1" -description = "World timezone definitions, modern and historical" -category = "main" -optional = false -python-versions = "*" - -[[package]] -name = "typing-extensions" -version = "4.0.1" -description = "Backported and Experimental Type Hints for Python 3.6+" -category = "main" -optional = false -python-versions = ">=3.6" - -[metadata] -lock-version = "1.1" -python-versions = "^3.7.0" -content-hash = "22731d3dcd696281e4beb78ee4fd91786321b3b5e4787b4ab44489f501e55538" - -[metadata.files] -pytz = [ - {file = "pytz-2022.1-py2.py3-none-any.whl", hash = "sha256:e68985985296d9a66a881eb3193b0906246245294a881e7c8afe623866ac6a5c"}, - {file = "pytz-2022.1.tar.gz", hash = "sha256:1e760e2fe6a8163bc0b3d9a19c4f84342afa0a2affebfaa84b01b978a02ecaa7"}, -] -typing-extensions = [ - {file = "typing_extensions-4.0.1-py3-none-any.whl", hash = "sha256:7f001e5ac290a0c0401508864c7ec868be4e701886d5b573a9528ed3973d9d3b"}, - {file = "typing_extensions-4.0.1.tar.gz", hash = "sha256:4ca091dea149f945ec56afb48dae714f21e8692ef22a395223bcd328961b6a0e"}, -] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/poetry.toml new/dirty-equals-0.5.0/poetry.toml --- old/dirty-equals-0.4/poetry.toml 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/poetry.toml 1970-01-01 01:00:00.000000000 +0100 @@ -1,2 +0,0 @@ -[virtualenvs] -create = false diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/pyproject.toml new/dirty-equals-0.5.0/pyproject.toml --- old/dirty-equals-0.4/pyproject.toml 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/pyproject.toml 2022-08-30 20:44:09.000000000 +0200 @@ -1,46 +1,51 @@ -[tool.poetry] -name = "dirty-equals" -version = "0" -description = "Doing dirty (but extremely useful) things with equals." -authors = ["Samuel Colvin <s...@muelcolvin.com>"] -readme = "README.md" -homepage = "https://dirty-equals.helpmanual.io" -repository = "https://github.com/samuelcolvin/dirty-equals" -license = "MIT" -classifiers = [ - "Development Status :: 4 - Beta", - "Framework :: Pytest", - "Intended Audience :: Developers", - "Intended Audience :: Education", - "Intended Audience :: Information Technology", - "Intended Audience :: Science/Research", - "Intended Audience :: System Administrators", - "Operating System :: Unix", - "Operating System :: POSIX :: Linux", - "Environment :: Console", - "Environment :: MacOS X", - "License :: OSI Approved :: MIT License", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Topic :: Software Development :: Libraries :: Python Modules", - "Topic :: Internet", - "Typing :: Typed", -] +[build-system] +requires = ['hatchling'] +build-backend = 'hatchling.build' -[tool.poetry.dependencies] -python = "^3.7.0" -typing-extensions = {version = "^4.0.1", python = "<3.8"} -pytz = ">=2021.3" +[tool.hatch.version] +path = 'dirty_equals/version.py' -[build-system] -requires = ["poetry-core"] -build-backend = "poetry.core.masonry.api" +[project] +name = 'dirty-equals' +description = 'Doing dirty (but extremely useful) things with equals.' +authors = [{name = 'Samuel Colvin', email = 's...@muelcolvin.com'}] +license = {file = 'LICENSE'} +readme = 'README.md' +classifiers = [ + 'Development Status :: 4 - Beta', + 'Framework :: Pytest', + 'Intended Audience :: Developers', + 'Intended Audience :: Education', + 'Intended Audience :: Information Technology', + 'Intended Audience :: Science/Research', + 'Intended Audience :: System Administrators', + 'Operating System :: Unix', + 'Operating System :: POSIX :: Linux', + 'Environment :: Console', + 'Environment :: MacOS X', + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 3 :: Only', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', + 'Topic :: Software Development :: Libraries :: Python Modules', + 'Topic :: Internet', + 'Typing :: Typed', +] +requires-python = '>=3.7' +dependencies = [ + 'typing-extensions>=4.0.1', + 'pytz>=2021.3', +] +dynamic = ['version'] -[tool.poetry-version-plugin] -source = "init" +[project.urls] +Homepage = 'https://github.com/samuelcolvin/dirty-equals' +Documentation = 'https://dirty-equals.helpmanual.io' +Funding = 'https://github.com/sponsors/samuelcolvin' +Source = 'https://github.com/samuelcolvin/dirty-equals' +Changelog = 'https://github.com/samuelcolvin/dirty-equals/releases' [tool.pytest.ini_options] testpaths = "tests" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/requirements/all.txt new/dirty-equals-0.5.0/requirements/all.txt --- old/dirty-equals-0.4/requirements/all.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/requirements/all.txt 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,4 @@ +-r ./docs.txt +-r ./linting.txt +-r ./tests.txt +-r ./pyproject.txt diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/requirements/docs.in new/dirty-equals-0.5.0/requirements/docs.in --- old/dirty-equals-0.4/requirements/docs.in 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/requirements/docs.in 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,5 @@ +black +mkdocs +mkdocs-material +mkdocs-simple-hooks +mkdocstrings[python] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/requirements/docs.txt new/dirty-equals-0.5.0/requirements/docs.txt --- old/dirty-equals-0.4/requirements/docs.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/requirements/docs.txt 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,89 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --output-file=requirements/docs.txt requirements/docs.in +# +black==22.6.0 + # via -r requirements/docs.in +click==8.1.3 + # via + # black + # mkdocs +ghp-import==2.1.0 + # via mkdocs +griffe==0.22.0 + # via mkdocstrings-python +importlib-metadata==4.12.0 + # via mkdocs +jinja2==3.1.2 + # via + # mkdocs + # mkdocs-material + # mkdocstrings +markdown==3.3.7 + # via + # mkdocs + # mkdocs-autorefs + # mkdocs-material + # mkdocstrings + # pymdown-extensions +markupsafe==2.1.1 + # via + # jinja2 + # mkdocstrings +mergedeep==1.3.4 + # via mkdocs +mkdocs==1.3.1 + # via + # -r requirements/docs.in + # mkdocs-autorefs + # mkdocs-material + # mkdocs-simple-hooks + # mkdocstrings +mkdocs-autorefs==0.4.1 + # via mkdocstrings +mkdocs-material==8.4.1 + # via -r requirements/docs.in +mkdocs-material-extensions==1.0.3 + # via mkdocs-material +mkdocs-simple-hooks==0.1.5 + # via -r requirements/docs.in +mkdocstrings[python]==0.19.0 + # via + # -r requirements/docs.in + # mkdocstrings-python +mkdocstrings-python==0.7.1 + # via mkdocstrings +mypy-extensions==0.4.3 + # via black +packaging==21.3 + # via mkdocs +pathspec==0.9.0 + # via black +platformdirs==2.5.2 + # via black +pygments==2.13.0 + # via mkdocs-material +pymdown-extensions==9.5 + # via + # mkdocs-material + # mkdocstrings +pyparsing==3.0.9 + # via packaging +python-dateutil==2.8.2 + # via ghp-import +pyyaml==6.0 + # via + # mkdocs + # pyyaml-env-tag +pyyaml-env-tag==0.1 + # via mkdocs +six==1.16.0 + # via python-dateutil +tomli==2.0.1 + # via black +watchdog==2.1.9 + # via mkdocs +zipp==3.8.1 + # via importlib-metadata diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/requirements/linting.in new/dirty-equals-0.5.0/requirements/linting.in --- old/dirty-equals-0.4/requirements/linting.in 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/requirements/linting.in 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,9 @@ +black +flake8 +flake8-quotes +isort[colors] +mypy +pre-commit +pycodestyle +pyflakes +types-pytz diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/requirements/linting.txt new/dirty-equals-0.5.0/requirements/linting.txt --- old/dirty-equals-0.4/requirements/linting.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/requirements/linting.txt 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,71 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --output-file=requirements/linting.txt requirements/linting.in +# +black==22.6.0 + # via -r requirements/linting.in +cfgv==3.3.1 + # via pre-commit +click==8.1.3 + # via black +colorama==0.4.5 + # via isort +distlib==0.3.6 + # via virtualenv +filelock==3.8.0 + # via virtualenv +flake8==5.0.4 + # via + # -r requirements/linting.in + # flake8-quotes +flake8-quotes==3.3.1 + # via -r requirements/linting.in +identify==2.5.3 + # via pre-commit +isort[colors]==5.10.1 + # via -r requirements/linting.in +mccabe==0.7.0 + # via flake8 +mypy==0.971 + # via -r requirements/linting.in +mypy-extensions==0.4.3 + # via + # black + # mypy +nodeenv==1.7.0 + # via pre-commit +pathspec==0.9.0 + # via black +platformdirs==2.5.2 + # via + # black + # virtualenv +pre-commit==2.20.0 + # via -r requirements/linting.in +pycodestyle==2.9.1 + # via + # -r requirements/linting.in + # flake8 +pyflakes==2.5.0 + # via + # -r requirements/linting.in + # flake8 +pyyaml==6.0 + # via pre-commit +toml==0.10.2 + # via pre-commit +tomli==2.0.1 + # via + # black + # mypy +types-pytz==2022.2.1.0 + # via -r requirements/linting.in +typing-extensions==4.3.0 + # via mypy +virtualenv==20.16.4 + # via pre-commit + +# The following packages are considered to be unsafe in a requirements file: +# setuptools diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/requirements/pyproject.txt new/dirty-equals-0.5.0/requirements/pyproject.txt --- old/dirty-equals-0.4/requirements/pyproject.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/requirements/pyproject.txt 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,10 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --output-file=requirements/pyproject.txt pyproject.toml +# +pytz==2022.2.1 + # via dirty-equals (pyproject.toml) +typing-extensions==4.3.0 + # via dirty-equals (pyproject.toml) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/requirements/tests.in new/dirty-equals-0.5.0/requirements/tests.in --- old/dirty-equals-0.4/requirements/tests.in 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/requirements/tests.in 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,4 @@ +coverage[toml] +pytest +pytest-mock +pytest-sugar diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/requirements/tests.txt new/dirty-equals-0.5.0/requirements/tests.txt --- old/dirty-equals-0.4/requirements/tests.txt 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/requirements/tests.txt 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,37 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --output-file=requirements/testing.txt requirements/testing.in +# +attrs==22.1.0 + # via pytest +coverage[toml]==6.4.4 + # via -r requirements/testing.in +iniconfig==1.1.1 + # via pytest +packaging==21.3 + # via + # pytest + # pytest-sugar +pluggy==1.0.0 + # via pytest +py==1.11.0 + # via pytest +pyparsing==3.0.9 + # via packaging +pytest==7.1.2 + # via + # -r requirements/testing.in + # pytest-mock + # pytest-sugar +pytest-mock==3.8.2 + # via -r requirements/testing.in +pytest-sugar==0.9.5 + # via -r requirements/testing.in +termcolor==1.1.0 + # via pytest-sugar +tomli==2.0.1 + # via + # coverage + # pytest diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/setup.py new/dirty-equals-0.5.0/setup.py --- old/dirty-equals-0.4/setup.py 1970-01-01 01:00:00.000000000 +0100 +++ new/dirty-equals-0.5.0/setup.py 2022-08-30 20:44:09.000000000 +0200 @@ -0,0 +1,27 @@ +import sys + +sys.stderr.write( + """ +=============================== +Unsupported installation method +=============================== +dirty-equals no longer supports installation with `python setup.py install`. +Please use `python -m pip install .` instead. +""" +) +sys.exit(1) + + +# The below code will never execute, however GitHub is particularly +# picky about where it finds Python packaging metadata. +# See: https://github.com/github/feedback/discussions/6456 +# +# To be removed once GitHub catches up. + +setup( + name='dirty-equals', + install_requires=[ + 'typing-extensions>=4.0.1', + 'pytz>=2021.3', + ], +) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/tests/mypy_checks.py new/dirty-equals-0.5.0/tests/mypy_checks.py --- old/dirty-equals-0.4/tests/mypy_checks.py 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/tests/mypy_checks.py 2022-08-30 20:44:09.000000000 +0200 @@ -1,12 +1,16 @@ """ This module is run with mypy to check types can be used correctly externally. """ -from dirty_equals import HasName, HasRepr, IsStr +import sys + +sys.path.append('.') + +from dirty_equals import HasName, HasRepr, IsStr # noqa E402 assert 123 == HasName('int') assert 123 == HasRepr('123') assert 123 == HasName(IsStr(regex='i..')) assert 123 == HasRepr(IsStr(regex=r'\d{3}')) -# type ignore is required (if it wasn't, there would be an error +# type ignore is required (if it wasn't, there would be an error) assert 123 != HasName(123) # type: ignore[arg-type] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/tests/requirements-linting.txt new/dirty-equals-0.5.0/tests/requirements-linting.txt --- old/dirty-equals-0.4/tests/requirements-linting.txt 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/tests/requirements-linting.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,9 +0,0 @@ -black==22.3.0 -flake8==4.0.1 -flake8-quotes==3.3.1 -isort[colors]==5.10.1 -mypy==0.942 -pre-commit==2.17.0 -pycodestyle==2.8.0 -pyflakes==2.4.0 -types-pytz==2021.3.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/tests/requirements.txt new/dirty-equals-0.5.0/tests/requirements.txt --- old/dirty-equals-0.4/tests/requirements.txt 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/tests/requirements.txt 1970-01-01 01:00:00.000000000 +0100 @@ -1,5 +0,0 @@ -coverage[toml]==6.3.2 -poetry==1.2.0a2 -pytest==7.1.1 -pytest-mock==3.7.0 -pytest-sugar==0.9.4 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/tests/test_datetime.py new/dirty-equals-0.5.0/tests/test_datetime.py --- old/dirty-equals-0.4/tests/test_datetime.py 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/tests/test_datetime.py 2022-08-30 20:44:09.000000000 +0200 @@ -1,4 +1,5 @@ from datetime import date, datetime, timedelta, timezone +from unittest.mock import Mock import pytest import pytz @@ -25,7 +26,6 @@ ), pytest.param('28/01/87', IsDatetime(approx=datetime(2000, 1, 1)), False, id='string-format-different'), pytest.param('foobar', IsDatetime(approx=datetime(2000, 1, 1)), False, id='string-format-wrong'), - pytest.param(datetime.now().isoformat(), IsNow(iso_string=True), True, id='isnow-str-true'), pytest.param(datetime(2000, 1, 1).isoformat(), IsNow(iso_string=True), False, id='isnow-str-different'), pytest.param([1, 2, 3], IsDatetime(approx=datetime(2000, 1, 1)), False, id='wrong-type'), pytest.param( @@ -121,6 +121,12 @@ assert IsNow(delta=3600.1).delta == timedelta(seconds=3600, microseconds=100000) +def test_is_now_relative(monkeypatch): + mock = Mock(return_value=datetime(2020, 1, 1, 12, 13, 14)) + monkeypatch.setattr(IsNow, '_get_now', mock) + assert IsNow() == datetime(2020, 1, 1, 12, 13, 14) + + def test_tz(): new_year_london = pytz.timezone('Europe/London').localize(datetime(2000, 1, 1)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/dirty-equals-0.4/tests/test_other.py new/dirty-equals-0.5.0/tests/test_other.py --- old/dirty-equals-0.4/tests/test_other.py 2022-04-28 17:37:25.000000000 +0200 +++ new/dirty-equals-0.5.0/tests/test_other.py 2022-08-30 20:44:09.000000000 +0200 @@ -1,8 +1,9 @@ import uuid +from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network import pytest -from dirty_equals import FunctionCheck, IsJson, IsUUID +from dirty_equals import FunctionCheck, IsIP, IsJson, IsUUID @pytest.mark.parametrize( @@ -128,3 +129,57 @@ def test_json_both(): with pytest.raises(TypeError, match='IsJson requires either an argument or kwargs, not both'): IsJson(1, a=2) + + +@pytest.mark.parametrize( + 'other,dirty', + [ + (IPv4Address('127.0.0.1'), IsIP()), + (IPv4Network('43.48.0.0/12'), IsIP()), + (IPv6Address('::eeff:ae3f:d473'), IsIP()), + (IPv6Network('::eeff:ae3f:d473/128'), IsIP()), + ('2001:0db8:0a0b:12f0:0000:0000:0000:0001', IsIP()), + ('179.27.154.96', IsIP), + ('43.62.123.119', IsIP(version=4)), + ('::ffff:2b3e:7b77', IsIP(version=6)), + ('0:0:0:0:0:ffff:2b3e:7b77', IsIP(version=6)), + ('54.43.53.219/10', IsIP(version=4, netmask='255.192.0.0')), + ('::ffff:aebf:d473/12', IsIP(version=6, netmask='fff0::')), + ('2001:0db8:0a0b:12f0:0000:0000:0000:0001', IsIP(version=6)), + (3232235521, IsIP()), + (b'\xC0\xA8\x00\x01', IsIP()), + (338288524927261089654018896845572831328, IsIP(version=6)), + (b'\x20\x01\x06\x58\x02\x2a\xca\xfe\x02\x00\x00\x00\x00\x00\x00\x01', IsIP(version=6)), + ], +) +def test_is_ip_true(other, dirty): + assert other == dirty + + +@pytest.mark.parametrize( + 'other,dirty', + [ + ('foobar', IsIP()), + ([1, 2, 3], IsIP()), + ('210.115.28.193', IsIP(version=6)), + ('::ffff:d273:1cc1', IsIP(version=4)), + ('210.115.28.193/12', IsIP(version=6, netmask='255.255.255.0')), + ('::ffff:d273:1cc1', IsIP(version=6, netmask='fff0::')), + (3232235521, IsIP(version=6)), + (338288524927261089654018896845572831328, IsIP(version=4)), + ], +) +def test_is_ip_false(other, dirty): + assert other != dirty + + +def test_not_ip_repr(): + is_ip = IsIP() + with pytest.raises(AssertionError): + assert '123' == is_ip + assert str(is_ip) == 'IsIP()' + + +def test_ip_bad_netmask(): + with pytest.raises(TypeError, match='To check the netmask you must specify the IP version'): + IsIP(netmask='255.255.255.0')