truera / trulens

Evaluation and Tracking for LLM Experiments
https://www.trulens.org/
MIT License
2.11k stars 182 forks source link

[BUG] AttributeError: 'PosixPath' object has no attribute 'endswith' #1316

Closed lorenzobalzani closed 2 months ago

lorenzobalzani commented 2 months ago

Bug Description I get this error:

AttributeError: 'PosixPath' object has no attribute 'endswith'

To Reproduce

from trulens_eval import Feedback

Expected behavior The error should not happen.

Relevant Logs/Tracebacks

2024-07-31 14:42:51.823 Uncaught app exception
Traceback (most recent call last):
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 589, in _run_script
    exec(code, module.__dict__)
  File "/path/to/entrypoint.py", line 69, in <module>
    main()
  File "/path/to/entrypoint.py", line 64, in main
    pg.run()
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/streamlit/navigation/page.py", line 286, in run
    exec(code, module.__dict__)
  File "/path/to/routes/chat.py", line 22, in <module>
    from promdc.backend.pipeline import Pipeline
  File "/path/to/pipeline.py", line 17, in <module>
    from .evaluation.evaluation import Evaluator
  File "/path/to/evaluation.py", line 1, in <module>
    from trulens_eval import Feedback
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/trulens_eval/__init__.py", line 16, in <module>
    from trulens_eval.utils.imports import check_imports
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/trulens_eval/utils/imports.py", line 20, in <module>
    from pip._internal.req import parse_requirements
  File "<frozen importlib._bootstrap>", line 1176, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1138, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1078, in _find_spec
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/_distutils_hack/__init__.py", line 90, in find_spec
    return method()
           ^^^^^^^^
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/_distutils_hack/__init__.py", line 138, in spec_for_pip
    if sys.version_info >= (3, 12) or self.pip_imported_during_build():
                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/_distutils_hack/__init__.py", line 150, in pip_imported_during_build
    return any(
           ^^^^
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/_distutils_hack/__init__.py", line 151, in <genexpr>
    cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None)
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/path/to/envs/prometeia/lib/python3.11/site-packages/_distutils_hack/__init__.py", line 160, in frame_file_is_setup
    return frame.f_globals.get('__file__', '').endswith('setup.py')
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'PosixPath' object has no attribute 'endswith'

Environment:

Context I am running a Streamlit environment.

@sfc-gh-chu @sfc-gh-jreini

dosubot[bot] commented 2 months ago

Hello @lorenzobalzani 👋, I'm here to help you with any bugs, questions, or contributions you may have. Let's work together to resolve the issue you're experiencing.

The issue you're encountering is due to the use of pip._internal.req.parse_requirements, which is not reliable and can cause the PosixPath object error. You can resolve this by modifying the requirements_of_file function to use the packaging.requirements module instead.

Here's a modified version of the requirements_of_file function that avoids using pip._internal.req.parse_requirements:

from packaging.requirements import Requirement
from pathlib import Path
from typing import Dict

def requirements_of_file(path: Path) -> Dict[str, Requirement]:
    """Get a dictionary of package names to requirements from a requirements file."""

    with path.open() as f:
        lines = f.readlines()

    mapping = {}
    for line in lines:
        line = line.strip()
        if line and not line.startswith("#"):
            req = Requirement(line)
            mapping[req.name] = req

    return mapping

To integrate this into your setup.py script, you can replace the parse_requirements calls with this function:

from pathlib import Path

required_packages = list(
    map(
        lambda req: str(req),
        requirements_of_file(Path("trulens_eval/requirements.txt")).values()
    )
)
optional_packages = list(
    map(
        lambda req: str(req),
        requirements_of_file(Path("trulens_eval/requirements.optional.txt")).values()
    )
)

This approach should resolve the PosixPath issue and ensure compatibility with your environment [1][2].

To continue talking to Dosu, mention @dosu.

lorenzobalzani commented 2 months ago

I do think that this LLM response does not resolve the issue @sfc-gh-dhuang.

sfc-gh-pdharmana commented 2 months ago

Hey @lorenzobalzani I tried to reproduce error locally and could not do it. One question: you mentioned python version as 3.12 but the error trace mentions the version as 3.11. Could you please check the environment?

lorenzobalzani commented 2 months ago

Hey @lorenzobalzani I tried to reproduce error locally and could not do it. One question: you mentioned python version as 3.12 but the error trace mentions the version as 3.11. Could you please check the environment?

That's my bad, I've figured out the solution and forgot to update the post. I solved by using an environment with >= Python 3.12.