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

AttributeError: type object 'Path' has no attribute '_flavour' #553

Closed
giladreti opened this issue Sep 13, 2020 · 9 comments
Closed

AttributeError: type object 'Path' has no attribute '_flavour' #553

giladreti opened this issue Sep 13, 2020 · 9 comments
Labels

Comments

@giladreti
Copy link

giladreti commented Sep 13, 2020

Describe the bug
pathlib claims that Path has no _flavour when module is marked for skip. When the module is not marked for skip it works just fine.

Traceback (most recent call last):
  File "c:\Users\gilad\Documents\my_module\test.py", line 10, in <module>
    test()
  File "c:\Users\gilad\Documents\my_module\test.py", line 8, in test
    my_func()
  File "c:\Users\gilad\Documents\my_module\my_file.py", line 5, in my_func
    Path('test.py')
  File "C:\Users\gilad\AppData\Local\Programs\Python\Python38\lib\pathlib.py", line 1038, in __new__
    self = cls._from_parts(args, init=False)
  File "C:\Users\gilad\AppData\Local\Programs\Python\Python38\lib\pathlib.py", line 679, in _from_parts
    drv, root, parts = self._parse_args(args)
  File "C:\Users\gilad\AppData\Local\Programs\Python\Python38\lib\pathlib.py", line 672, in _parse_args
    return cls._flavour.parse_parts(parts)
AttributeError: type object 'Path' has no attribute '_flavour'

How To Reproduce
I have the following setup:

.
├── __init__.py
├── __pycache__
│   ├── __init__.cpython-38.pyc
│   ├── my_file.cpython-38.pyc
│   └── test.cpython-38-pytest-6.0.2.pyc
├── my_file.py
└── test.py

test.py:

from pyfakefs.fake_filesystem_unittest import Patcher

from my_file import my_func

def test():
    with Patcher(additional_skip_names=['my_file']):
        my_func()

test()

my_file.py:

import os

def my_func():
    os.open('test.py', os.O_RDONLY, 0o777) # works!

    Path('test.py') # fails...

Your enviroment

python -c "import platform; print(platform.platform())"
python -c "import sys; print('Python', sys.version)"
python -c "from pyfakefs.fake_filesystem import __version__; print('pyfakefs', __version__)"

The output is as follows:

Windows-10-10.0.19041-SP0
Python 3.8.3 (tags/v3.8.3:6f8c832, May 13 2020, 22:37:02) [MSC v.1924 64 bit (AMD64)]
pyfakefs 4.1.0
@mrbean-bremen
Copy link
Member

mrbean-bremen commented Sep 13, 2020

The call stack does not match your my_file.py listing - I guess this is copy-and-pasted from the other issue.

@giladreti
Copy link
Author

Sorry, I have edited it now.

@mrbean-bremen
Copy link
Member

mrbean-bremen commented Sep 24, 2020

Just for the record: the problem here is that while the pathlib used in the skipped module is not patched, the original pathlib (used in this case) is patched to use the fake Path. This is needed because most of pathlib is used in the fake version, so we cannot just just change this, as it would break modules that use the patched pathlib. It also doesn't help to change the behavior of the fake Path to use the real class if needed, because it doesn't get to this point. pathlib makes an identity check for the contained Path early on, which would always fail for the fake path class.
I have a rough idea how to fix this (always use a patched version of pathlib that overrides that check and change the behavior accordingly), but that would be quite clumsy, as we will need an exception for pathlib in the generic patching, and the pathlib code itself would also get more messy.
I will see if I get a better idea - in any case this may take some time (unexpectedly, the open problem was easier to handle).

@BrendanSimon
Copy link

BrendanSimon commented Mar 3, 2022

I'm am getting this error in 2022.
Is it supposed to be fixed now?
Is there an issue that tracks this "bug"?

NOTE: I'm using Python 3.7.3 on Debian 10 Buster for my unit testing, and my real code runs on Python 2.7.16 (with pathlib2) on a Debian 10 Buster embedded system (yes, I know 2.7 is unmaintained - the migration to Python 3 is on my wish list).

Is there a 3rd party (updated) version of pathlib.Path which can be used as an alternative, perhaps? I noticed pathlib3x on PyPi

Thanks :)

@BrendanSimon
Copy link

BrendanSimon commented Mar 4, 2022

I can confirm installing pathlib3x in my dev environment (and modifying my production code accordingly) that I was able to get my unit test to complete without the error "type object 'Path' has not attribute '_flavour'" (using python 3.7.3) :)

@mrbean-bremen
Copy link
Member

@BrendanSimon - this specific problem has been fixed with the commit that closed this issue - it had to do with pathlib used in skipped modules.

If I understand this correctly, your problem was using pathlib2 under Python3, which has less options than pathlib itself - is that correct?
We do have some support for pathlib2, but there have been some problems with later Python versions due to new features, and the support for pathlib2 is no longer maintained, as it it not needed anymore. I wasn't aware of pathlib3x - good to know!
So, If I understand this correctly, you have resolved the problem by using pathlib3x, and there is nothing we should do here? Otherwise, please file a new issue with your concrete problem.

@dhofstetter
Copy link

@mrbean-bremen I guess this problem still remains.

In case of pyfakesfs usage when you try to construct a Path

The reason is located here pathlib.Path.__new__

 if cls is Path:
    cls = WindowsPath if os.name == 'nt' else PosixPath     
self = cls._from_parts(args)

This leads to more or less this call when using the pyfakefs

Path._from_parts(args)
# instead of 
PosixPath._from_parts(....)  

The error is indicated like this:

cls = <class 'pathlib.Path'>, args = ('/tmp/scopes.toml',)

>   ???
E   AttributeError: type object 'Path' has no attribute '_flavour'

For sake of completion (I already tried to reload some modules but it won't work ...)

@pytest.mark.parametrize("fs", [
        [None, [pydantic._internal._std_types_schema]]
    ], indirect=True)
    def test_scopes_from_toml(fs: FakeFilesystem):
        fs.os = OSType.LINUX
        fs.create_file("/tmp/scopes.toml", contents="""
    openid = "Standard"
    test = "test"
    """
        )
>       settings = KeycloakSettings(
            server_url="https://example.com/auth",
            flows={"Oauth2ClientCredentialsBearer"},
            audience="https://api.example.com",
            realm="realm",
            scopes="/tmp/scopes.toml"
        )

/Users/dh/Development/yio/yio/yio-fastapi-utils/tests/security/test_config.py:80: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/Users/dh/Development/yio/yio/yio-fastapi-utils/venv/lib/python3.11/site-packages/pydantic_settings/main.py:71: in __init__
    super().__init__(
/Users/dh/Development/yio/yio/yio-fastapi-utils/venv/lib/python3.11/site-packages/pydantic/_internal/_std_types_schema.py:235: in path_validator
    return construct_path(input_value)
/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/pathlib.py:871: in __new__
    ???
/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/pathlib.py:509: in _from_parts
    ???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

cls = <class 'pathlib.Path'>, args = ('/tmp/scopes.toml',)

>   ???
E   AttributeError: type object 'Path' has no attribute '_flavour'

/opt/homebrew/Cellar/[email protected]/3.11.3/Frameworks/Python.framework/Versions/3.11/lib/python3.11/pathlib.py:502: AttributeError

@dhofstetter
Copy link

I was able to narrow down this problem.

It seems to occur because Pydantic constructs its models with the original path cls and pyfakefs is later patching it.

if I subclass the model in my unitest it works, because the validators get built with the patched Path version internally.

....
class NewModel(OriginalModel):
    pass
....

@mrbean-bremen
Copy link
Member

Ah yes, this is a known limitation.

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

No branches or pull requests

4 participants