Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IsUrl seems to be broken with pydantic-2 #72

Closed
mgorny opened this issue Jul 6, 2023 · 7 comments · Fixed by #88
Closed

IsUrl seems to be broken with pydantic-2 #72

mgorny opened this issue Jul 6, 2023 · 7 comments · Fixed by #88

Comments

@mgorny
Copy link
Contributor

mgorny commented Jul 6, 2023

After upgrading to pydantic-2.0.2, I'm getting the following test failures:

$ python -m pytest -Wignore
========================================================= test session starts =========================================================
platform linux -- Python 3.11.4, pytest-7.4.0, pluggy-1.2.0
rootdir: /tmp/dirty-equals
configfile: pyproject.toml
testpaths: tests
plugins: examples-0.0.9
collected 599 items                                                                                                                   

tests/test_base.py .............................                                                                                [  4%]
tests/test_boolean.py ............................................                                                              [ 12%]
tests/test_datetime.py .................................................                                                        [ 20%]
tests/test_dict.py ..........................................................                                                   [ 30%]
tests/test_docs.py ...........F...............................................                                                  [ 39%]
tests/test_inspection.py ............................                                                                           [ 44%]
tests/test_list_tuple.py ..............................................................................                         [ 57%]
tests/test_numeric.py ...................................................................................                       [ 71%]
tests/test_other.py ...............................................................................FFF......................... [ 89%]
.....                                                                                                                           [ 90%]
tests/test_strings.py ...........................................................                                               [100%]

============================================================== FAILURES ===============================================================
___________________________________________ test_docstrings[dirty_equals/_other.py:197-206] ___________________________________________

example = CodeExample(source="from dirty_equals import IsUrl\n\nassert 'https://example.com' == IsUrl\nassert 'https://example.c...'ee58e62f-4c92-48e3-acd1-f765815e3bd5'), test_id='tests/test_docs.py::test_docstrings[dirty_equals/_other.py:197-206]')
eval_example = <pytest_examples.eval_example.EvalExample object at 0x7fa2a1104510>

    @pytest.mark.skipif(platform.python_implementation() == 'PyPy', reason='PyPy does not allow metaclass dunder methods')
    @pytest.mark.parametrize('example', find_examples('dirty_equals', 'docs'), ids=str)
    def test_docstrings(example: CodeExample, eval_example: EvalExample):
        prefix_settings = example.prefix_settings()
        # E711 and E712 refer to `== True` and `== None` and need to be ignored
        # I001 refers is a problem with black and ruff disagreeing about blank lines :shrug:
        eval_example.set_config(ruff_ignore=['E711', 'E712', 'I001'])
    
        if prefix_settings.get('lint') != 'skip':
            if eval_example.update_examples:
                eval_example.format(example)
            else:
                eval_example.lint(example)
    
        if prefix_settings.get('test') != 'skip':
            if eval_example.update_examples:
                eval_example.run_print_update(example)
            else:
>               eval_example.run_print_check(example)

tests/test_docs.py:25: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

>   assert 'https://example.com' == IsUrl
    assert 'https://example.com' == IsUrl(tld='com')
    assert 'https://example.com' == IsUrl(scheme='https')
    assert 'https://example.com' != IsUrl(scheme='http')
    assert 'postgres://user:pass@localhost:5432/app' == IsUrl(postgres_dsn=True)
    assert 'postgres://user:pass@localhost:5432/app' != IsUrl(http_url=True)
    ```
    """
E   AssertionError: assert 'https://example.com' == IsUrl

dirty_equals/_other.py:200: AssertionError
_____________________________________________ test_is_url_true[https://example.com-IsUrl] _____________________________________________

other = 'https://example.com', dirty = IsUrl

    @pytest.mark.parametrize(
        'other,dirty',
        [
            ('https://example.com', IsUrl),
            ('https://example.com', IsUrl(scheme='https')),
            ('postgres://user:pass@localhost:5432/app', IsUrl(postgres_dsn=True)),
        ],
    )
    def test_is_url_true(other, dirty):
>       assert other == dirty
E       AssertionError: assert 'https://example.com' == IsUrl

tests/test_other.py:275: AssertionError
____________________________________________ test_is_url_true[https://example.com-dirty1] _____________________________________________

other = 'https://example.com', dirty = IsUrl(<class 'pydantic_core._pydantic_core.Url'>)

    @pytest.mark.parametrize(
        'other,dirty',
        [
            ('https://example.com', IsUrl),
            ('https://example.com', IsUrl(scheme='https')),
            ('postgres://user:pass@localhost:5432/app', IsUrl(postgres_dsn=True)),
        ],
    )
    def test_is_url_true(other, dirty):
>       assert other == dirty
E       AssertionError: assert 'https://example.com' == IsUrl(<class 'pydantic_core._pydantic_core.Url'>)

tests/test_other.py:275: AssertionError
__________________________________ test_is_url_true[postgres://user:pass@localhost:5432/app-dirty2] ___________________________________

other = 'postgres://user:pass@localhost:5432/app'
dirty = IsUrl(typing.Annotated[pydantic_core._pydantic_core.MultiHostUrl, UrlConstraints(max_length=None, allowed_schemes=['po...+py-postgresql', 'postgresql+pygresql'], host_required=True, default_host=None, default_port=None, default_path=None)])

    @pytest.mark.parametrize(
        'other,dirty',
        [
            ('https://example.com', IsUrl),
            ('https://example.com', IsUrl(scheme='https')),
            ('postgres://user:pass@localhost:5432/app', IsUrl(postgres_dsn=True)),
        ],
    )
    def test_is_url_true(other, dirty):
>       assert other == dirty
E       AssertionError: assert 'postgres://user:pass@localhost:5432/app' == IsUrl(typing.Annotated[pydantic_core._pydantic_core.MultiHostUrl, UrlConstraints(max_length=None, allowed_schemes=['po...+py-postgresql', 'postgresql+pygresql'], host_required=True, default_host=None, default_port=None, default_path=None)])

tests/test_other.py:275: AssertionError
======================================================= short test summary info =======================================================
FAILED tests/test_docs.py::test_docstrings[dirty_equals/_other.py:197-206] - AssertionError: assert 'https://example.com' == IsUrl
FAILED tests/test_other.py::test_is_url_true[https://example.com-IsUrl] - AssertionError: assert 'https://example.com' == IsUrl
FAILED tests/test_other.py::test_is_url_true[https://example.com-dirty1] - AssertionError: assert 'https://example.com' == IsUrl(<class 'pydantic_core._pydantic_core.Url'>)
FAILED tests/test_other.py::test_is_url_true[postgres://user:pass@localhost:5432/app-dirty2] - AssertionError: assert 'postgres://user:pass@localhost:5432/app' == IsUrl(typing.Annotated[pydantic_core._pydantic_core.MultiHostU...
==================================================== 4 failed, 595 passed in 1.54s ====================================================

They pass after downgrading pydantic to <2.

gentoo-bot pushed a commit to gentoo/gentoo that referenced this issue Jul 6, 2023
Bug: samuelcolvin/dirty-equals#72
Signed-off-by: Michał Górny <mgorny@gentoo.org>
@samuelcolvin
Copy link
Owner

Good catch, I'll look into it.

samuelcolvin pushed a commit that referenced this issue Sep 3, 2023
Closes issue #72

Co-authored-by: Shagov <shagov@tochka.com>
@gotmax23
Copy link

#74 apparently does not fix this issue either.

=================================== FAILURES ===================================
_________________ test_is_url_true[https://example.com-IsUrl] __________________

other = 'https://example.com', dirty = IsUrl

    @pytest.mark.parametrize(
        'other,dirty',
        [
            ('https://example.com', IsUrl),
            ('https://example.com', IsUrl(scheme='https')),
            ('postgres://user:pass@localhost:5432/app', IsUrl(postgres_dsn=True)),
        ],
    )
    def test_is_url_true(other, dirty):
>       assert other == dirty
E       AssertionError: assert 'https://example.com' == IsUrl

tests/test_other.py:275: AssertionError
_________________ test_is_url_true[https://example.com-dirty1] _________________

other = 'https://example.com'
dirty = IsUrl(<class 'pydantic_core._pydantic_core.Url'>)

    @pytest.mark.parametrize(
        'other,dirty',
        [
            ('https://example.com', IsUrl),
            ('https://example.com', IsUrl(scheme='https')),
            ('postgres://user:pass@localhost:5432/app', IsUrl(postgres_dsn=True)),
        ],
    )
    def test_is_url_true(other, dirty):
>       assert other == dirty
E       AssertionError: assert 'https://example.com' == IsUrl(<class 'pydantic_core._pydantic_core.Url'>)

tests/test_other.py:275: AssertionError

@alexmojaki
Copy link
Contributor

There's a few problems here:

  1. requirements/linting.txt specifies pydantic==1.10.7. Tests should really be running with pydantic v2 by default which would have picked up the problem, maybe even both v1 and v2 in CI.
  2. IsUrl uses parse_obj_as which is deprecated in pydantic v2, and the warning triggers a failure in pytest.
  3. equal = parsed.unicode_string() == other is False because parsed.unicode_string() is 'https://example.com/' but other is 'https://example.com' (no trailing slash). Of course the check could deal with trailing slashes specifically, but it seems likely that there are other similar edge cases to worry about. I don't know what the purpose of this check is anyway, the tests all pass if I remove it entirely, along with the equal variable.
  4. One of the doctests fails because the attribute tld no longer exists on URLs in v2.

@mgorny
Copy link
Contributor Author

mgorny commented Nov 6, 2023

Ping.

@dutyrok
Copy link

dutyrok commented Nov 14, 2023

I was able to fix this issue by next way. May be it helps for upstream.
dirty-equals-alt-fix-IsUrl-for-pydanticV2.patch.txt

@samuelcolvin
Copy link
Owner

sorry, life has been pretty busy. Looking into this.

samuelcolvin added a commit that referenced this issue Nov 14, 2023
fix #72

Ended up having to do a bunch of things at the same time to get tests to
pass:
* drop 3.7 (added 3.12 at the same time)
* uprev deps
* uprev pydantic requirement to >2
* switch `IsUrl` to assume pydantic 2
@mgorny
Copy link
Contributor Author

mgorny commented Nov 14, 2023

Thank you to you all!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants