Skip to content

Regressions related to URL formation in Python 3.14 #596

Open
@musicinmybrain

Description

@musicinmybrain

To demonstrate this, I first have to get the tests working on Python 3.13. I skip ftpfs download tests to avoid flaky failures noted in #595.

$ git clone https://github.com/PyFilesystem/pyfilesystem2.git
$ cd pyfilesystem2
$ git branch py314
$ git checkout py314
$ curl -L -O https://github.com/PyFilesystem/pyfilesystem2/pull/570.patch
$ git am 570.patch
$ curl -L -O https://github.com/PyFilesystem/pyfilesystem2/pull/587.patch
$ git am 587.patch
$ curl -L -O https://github.com/PyFilesystem/pyfilesystem2/pull/595.patch
$ git am 595.patch
$ python3 --version
Python 3.13.3
$ python3 -m venv _e
$ . _e/bin/activate
(_e) $ pip install -e .
(_e) $ pip install -r tests/requirements.txt pytest
(_e) $ pytest -k 'not TestFTPFS'
[…]
=================== 2463 passed, 24 skipped, 193 deselected, 32 warnings in 15.70s ===================

Now, repeating the same steps with Python 3.14:

(_e) $ deactivate
$ python3.14 --version
Python 3.14.0b2
$ python3.14 -m venv _f
$ . _f/bin/activate
(_f) $ pip install -e .
(_f) $ pip install -r tests/requirements.txt pytest
(_f) $ pytest -k 'not TestFTPFS'
[…]
tests/test_ftpfs.py ..Fatal Python error: Segmentation fault

Current thread 0x00007ffaff251bc0 [pytest] (most recent call first):
  File "/home/ben/src/forks/pyfilesystem2/_f/lib64/python3.14/site-packages/cryptography/hazmat/bindings/openssl/binding.py", line 50 in build_conditional_library
  File "/home/ben/src/forks/pyfilesystem2/_f/lib64/python3.14/site-packages/cryptography/hazmat/bindings/openssl/binding.py", line 72 in _ensure_ffi_initialized
  File "/home/ben/src/forks/pyfilesystem2/_f/lib64/python3.14/site-packages/cryptography/hazmat/bindings/openssl/binding.py", line 79 in init_static_locks
  File "/home/ben/src/forks/pyfilesystem2/_f/lib64/python3.14/site-packages/cryptography/hazmat/bindings/openssl/binding.py", line 110 in <module>
[…]

Ok, that appears to be an issue with the current PyPI wheels for cryptography; let’s omit tests/test_ftpfs.py entirely for now.

(_f) $ pytest --ignore tests/test_ftpfs.py
[…]
============================================== FAILURES ==============================================
____________________________________ TestOSFS.test_complex_geturl ____________________________________

self = <tests.test_osfs.TestOSFS testMethod=test_complex_geturl>

    def test_complex_geturl(self):
        self.fs.makedirs("foo/bar ha")
        test_fixtures = [
            # test file, expected url path
            ["foo", "foo"],
            ["foo-bar", "foo-bar"],
            ["foo_bar", "foo_bar"],
            ["foo/bar ha/barz", "foo/bar%20ha/barz"],
            ["example b.txt", "example%20b.txt"],
            ["exampleㄓ.txt", "example%E3%84%93.txt"],
        ]
        file_uri_prefix = "osfs://"
        for test_file, relative_url_path in test_fixtures:
            self.fs.create(test_file)
            expected = file_uri_prefix + self.fs.getsyspath(relative_url_path).replace(
                "\\", "/"
            )
            actual = self.fs.geturl(test_file, purpose="fs")

>           self.assertEqual(actual, expected)
E           AssertionError: 'osfs://///tmp/tmpmmeyh_87fstestosfs/foo' != 'osfs:///tmp/tmpmmeyh_87fstestosfs/foo'
E           - osfs://///tmp/tmpmmeyh_87fstestosfs/foo
E           ?      --
E           + osfs:///tmp/tmpmmeyh_87fstestosfs/foo

tests/test_osfs.py:227: AssertionError
____________________________________ TestOSFS.test_complex_geturl ____________________________________

self = <tests.test_osfs.TestOSFS testMethod=test_complex_geturl>

    def test_complex_geturl(self):
        self.fs.makedirs("foo/bar ha")
        test_fixtures = [
            # test file, expected url path
            ["foo", "foo"],
            ["foo-bar", "foo-bar"],
            ["foo_bar", "foo_bar"],
            ["foo/bar ha/barz", "foo/bar%20ha/barz"],
            ["example b.txt", "example%20b.txt"],
            ["exampleㄓ.txt", "example%E3%84%93.txt"],
        ]
        file_uri_prefix = "osfs://"
        for test_file, relative_url_path in test_fixtures:
            self.fs.create(test_file)
            expected = file_uri_prefix + self.fs.getsyspath(relative_url_path).replace(
                "\\", "/"
            )
            actual = self.fs.geturl(test_file, purpose="fs")

>           self.assertEqual(actual, expected)
E           AssertionError: 'osfs://///tmp/tmpqbdqe7a2fstestosfs/foo' != 'osfs:///tmp/tmpqbdqe7a2fstestosfs/foo'
E           - osfs://///tmp/tmpqbdqe7a2fstestosfs/foo
E           ?      --
E           + osfs:///tmp/tmpqbdqe7a2fstestosfs/foo

tests/test_osfs.py:227: AssertionError
___________________________________ TestSubFS.test_complex_geturl ____________________________________

self = <tests.test_subfs.TestSubFS testMethod=test_complex_geturl>

    def test_complex_geturl(self):
        self.fs.makedirs("foo/bar ha")
        test_fixtures = [
            # test file, expected url path
            ["foo", "foo"],
            ["foo-bar", "foo-bar"],
            ["foo_bar", "foo_bar"],
            ["foo/bar ha/barz", "foo/bar%20ha/barz"],
            ["example b.txt", "example%20b.txt"],
            ["exampleㄓ.txt", "example%E3%84%93.txt"],
        ]
        file_uri_prefix = "osfs://"
        for test_file, relative_url_path in test_fixtures:
            self.fs.create(test_file)
            expected = file_uri_prefix + self.fs.getsyspath(relative_url_path).replace(
                "\\", "/"
            )
            actual = self.fs.geturl(test_file, purpose="fs")

>           self.assertEqual(actual, expected)
E           AssertionError: 'osfs://///tmp/tmprx2ztqhdfstest/__subdir__/foo' != 'osfs:///tmp/tmprx2ztqhdfstest/__subdir__/foo'
E           - osfs://///tmp/tmprx2ztqhdfstest/__subdir__/foo
E           ?      --
E           + osfs:///tmp/tmprx2ztqhdfstest/__subdir__/foo

tests/test_osfs.py:227: AssertionError
__________________________________ TestReadTarFS.test_geturl_for_fs __________________________________

self = <tests.test_tarfs.TestReadTarFS testMethod=test_geturl_for_fs>

    def test_geturl_for_fs(self):
        test_fixtures = [
            # test_file, expected
            ["foo/bar/egg/foofoo", "foo/bar/egg/foofoo"],
            ["foo/bar egg/foo foo", "foo/bar%20egg/foo%20foo"],
        ]
        tar_file_path = self._temp_path.replace("\\", "/")
        for test_file, expected_file in test_fixtures:
            expected = "tar://{tar_file_path}!/{file_inside_tar}".format(
                tar_file_path=tar_file_path, file_inside_tar=expected_file
            )
>           self.assertEqual(self.fs.geturl(test_file, purpose="fs"), expected)
E           AssertionError: 'tar://///tmp/tmp5z7bhtdw!/foo/bar/egg/foofoo' != 'tar:///tmp/tmp5z7bhtdw!/foo/bar/egg/foofoo'
E           - tar://///tmp/tmp5z7bhtdw!/foo/bar/egg/foofoo
E           ?     --
E           + tar:///tmp/tmp5z7bhtdw!/foo/bar/egg/foofoo

tests/test_tarfs.py:208: AssertionError
________________________________ TestReadTarFSMem.test_geturl_for_fs _________________________________

self = <tests.test_tarfs.TestReadTarFSMem testMethod=test_geturl_for_fs>

    def test_geturl_for_fs(self):
        test_fixtures = [
            # test_file, expected
            ["foo/bar/egg/foofoo", "foo/bar/egg/foofoo"],
            ["foo/bar egg/foo foo", "foo/bar%20egg/foo%20foo"],
        ]
        tar_file_path = self._temp_path.replace("\\", "/")
        for test_file, expected_file in test_fixtures:
            expected = "tar://{tar_file_path}!/{file_inside_tar}".format(
                tar_file_path=tar_file_path, file_inside_tar=expected_file
            )
>           self.assertEqual(self.fs.geturl(test_file, purpose="fs"), expected)
E           AssertionError: 'tar://///tmp/tmpwa9u0aba!/foo/bar/egg/foofoo' != 'tar:///tmp/tmpwa9u0aba!/foo/bar/egg/foofoo'
E           - tar://///tmp/tmpwa9u0aba!/foo/bar/egg/foofoo
E           ?     --
E           + tar:///tmp/tmpwa9u0aba!/foo/bar/egg/foofoo

tests/test_tarfs.py:208: AssertionError
____________________________________ TestOSFS.test_complex_geturl ____________________________________

self = <tests.test_osfs.TestOSFS testMethod=test_complex_geturl>

    def test_complex_geturl(self):
        self.fs.makedirs("foo/bar ha")
        test_fixtures = [
            # test file, expected url path
            ["foo", "foo"],
            ["foo-bar", "foo-bar"],
            ["foo_bar", "foo_bar"],
            ["foo/bar ha/barz", "foo/bar%20ha/barz"],
            ["example b.txt", "example%20b.txt"],
            ["exampleㄓ.txt", "example%E3%84%93.txt"],
        ]
        file_uri_prefix = "osfs://"
        for test_file, relative_url_path in test_fixtures:
            self.fs.create(test_file)
            expected = file_uri_prefix + self.fs.getsyspath(relative_url_path).replace(
                "\\", "/"
            )
            actual = self.fs.geturl(test_file, purpose="fs")

>           self.assertEqual(actual, expected)
E           AssertionError: 'osfs://///tmp/tmp9srq1bisfstestosfs/foo' != 'osfs:///tmp/tmp9srq1bisfstestosfs/foo'
E           - osfs://///tmp/tmp9srq1bisfstestosfs/foo
E           ?      --
E           + osfs:///tmp/tmp9srq1bisfstestosfs/foo

tests/test_osfs.py:227: AssertionError
___________________________________ TestTempFS.test_complex_geturl ___________________________________

self = <tests.test_tempfs.TestTempFS testMethod=test_complex_geturl>

    def test_complex_geturl(self):
        self.fs.makedirs("foo/bar ha")
        test_fixtures = [
            # test file, expected url path
            ["foo", "foo"],
            ["foo-bar", "foo-bar"],
            ["foo_bar", "foo_bar"],
            ["foo/bar ha/barz", "foo/bar%20ha/barz"],
            ["example b.txt", "example%20b.txt"],
            ["exampleㄓ.txt", "example%E3%84%93.txt"],
        ]
        file_uri_prefix = "osfs://"
        for test_file, relative_url_path in test_fixtures:
            self.fs.create(test_file)
            expected = file_uri_prefix + self.fs.getsyspath(relative_url_path).replace(
                "\\", "/"
            )
            actual = self.fs.geturl(test_file, purpose="fs")

>           self.assertEqual(actual, expected)
E           AssertionError: 'osfs://///tmp/tmpu46lay_a__tempfs__/foo' != 'osfs:///tmp/tmpu46lay_a__tempfs__/foo'
E           - osfs://///tmp/tmpu46lay_a__tempfs__/foo
E           ?      --
E           + osfs:///tmp/tmpu46lay_a__tempfs__/foo

tests/test_osfs.py:227: AssertionError
__________________________________ TestReadZipFS.test_geturl_for_fs __________________________________

self = <tests.test_zipfs.TestReadZipFS testMethod=test_geturl_for_fs>

    def test_geturl_for_fs(self):
        test_file = "foo/bar/egg/foofoo"
        expected = "zip://{zip_file_path}!/{file_inside_zip}".format(
            zip_file_path=self._temp_path.replace("\\", "/"), file_inside_zip=test_file
        )
>       self.assertEqual(self.fs.geturl(test_file, purpose="fs"), expected)
E       AssertionError: 'zip://///tmp/tmpn0pdowr6!/foo/bar/egg/foofoo' != 'zip:///tmp/tmpn0pdowr6!/foo/bar/egg/foofoo'
E       - zip://///tmp/tmpn0pdowr6!/foo/bar/egg/foofoo
E       ?     --
E       + zip:///tmp/tmpn0pdowr6!/foo/bar/egg/foofoo

tests/test_zipfs.py:177: AssertionError
________________________________ TestReadZipFSMem.test_geturl_for_fs _________________________________

self = <tests.test_zipfs.TestReadZipFSMem testMethod=test_geturl_for_fs>

    def test_geturl_for_fs(self):
        test_file = "foo/bar/egg/foofoo"
        expected = "zip://{zip_file_path}!/{file_inside_zip}".format(
            zip_file_path=self._temp_path.replace("\\", "/"), file_inside_zip=test_file
        )
>       self.assertEqual(self.fs.geturl(test_file, purpose="fs"), expected)
E       AssertionError: 'zip://///tmp/tmpx8ggt4qv!/foo/bar/egg/foofoo' != 'zip:///tmp/tmpx8ggt4qv!/foo/bar/egg/foofoo'
E       - zip://///tmp/tmpx8ggt4qv!/foo/bar/egg/foofoo
E       ?     --
E       + zip:///tmp/tmpx8ggt4qv!/foo/bar/egg/foofoo

tests/test_zipfs.py:177: AssertionError
========================================== warnings summary ==========================================
[…]
====================================== short test summary info =======================================
FAILED tests/test_osfs.py::TestOSFS::test_complex_geturl - AssertionError: 'osfs://///tmp/tmpmmeyh_87fstestosfs/foo' != 'osfs:///tmp/tmpmmeyh_87fstestosfs/foo'
FAILED tests/test_subfs.py::TestOSFS::test_complex_geturl - AssertionError: 'osfs://///tmp/tmpqbdqe7a2fstestosfs/foo' != 'osfs:///tmp/tmpqbdqe7a2fstestosfs/foo'
FAILED tests/test_subfs.py::TestSubFS::test_complex_geturl - AssertionError: 'osfs://///tmp/tmprx2ztqhdfstest/__subdir__/foo' != 'osfs:///tmp/tmprx2ztqhdfstes...
FAILED tests/test_tarfs.py::TestReadTarFS::test_geturl_for_fs - AssertionError: 'tar://///tmp/tmp5z7bhtdw!/foo/bar/egg/foofoo' != 'tar:///tmp/tmp5z7bhtdw!/foo/ba...
FAILED tests/test_tarfs.py::TestReadTarFSMem::test_geturl_for_fs - AssertionError: 'tar://///tmp/tmpwa9u0aba!/foo/bar/egg/foofoo' != 'tar:///tmp/tmpwa9u0aba!/foo/ba...
FAILED tests/test_tempfs.py::TestOSFS::test_complex_geturl - AssertionError: 'osfs://///tmp/tmp9srq1bisfstestosfs/foo' != 'osfs:///tmp/tmp9srq1bisfstestosfs/foo'
FAILED tests/test_tempfs.py::TestTempFS::test_complex_geturl - AssertionError: 'osfs://///tmp/tmpu46lay_a__tempfs__/foo' != 'osfs:///tmp/tmpu46lay_a__tempfs__/foo'
FAILED tests/test_zipfs.py::TestReadZipFS::test_geturl_for_fs - AssertionError: 'zip://///tmp/tmpn0pdowr6!/foo/bar/egg/foofoo' != 'zip:///tmp/tmpn0pdowr6!/foo/ba...
FAILED tests/test_zipfs.py::TestReadZipFSMem::test_geturl_for_fs - AssertionError: 'zip://///tmp/tmpx8ggt4qv!/foo/bar/egg/foofoo' != 'zip:///tmp/tmpx8ggt4qv!/foo/ba...
====================== 9 failed, 2365 passed, 23 skipped, 28 warnings in 14.53s ======================

All of these appear to be related to python/cpython#125974.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions