pypa / hatch

Modern, extensible Python project management
https://hatch.pypa.io/latest/
MIT License
5.74k stars 282 forks source link

AttributeError: 'WindowsPath' object has no attribute 'endswith' #1396

Closed balthild closed 3 months ago

balthild commented 3 months ago

Environment

Description

Command hatch env create fails with AttributeError: 'WindowsPath' object has no attribute 'endswith'. I can start hatch shell for the environment after this command fails, but the project package is not installed in the environment.

According to the output, the error occurs in the virtualenv package. However, when I try using virtualenv directly, there's no problem, so I'm not sure if this should be reported here or to virtualenv.

The command runs without error with the same project on Ubuntu.

D:\Projects\Python\myproject
❯ hatch env create
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\cli\__init__.py:221 in main  │
│                                                                                                  │
│   218                                                                                            │
│   219 def main():  # no cov                                                                      │
│   220 │   try:                                                                                   │
│ ❱ 221 │   │   return hatch(prog_name='hatch', windows_expand_args=False)                         │
│   222 │   except Exception:  # noqa: BLE001                                                      │
│   223 │   │   from rich.console import Console                                                   │
│   224                                                                                            │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1157 in __call__     │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1078 in main         │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1688 in invoke       │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1688 in invoke       │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1434 in invoke       │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:783 in invoke        │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\decorators.py:45 in new_func │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\cli\env\create.py:38 in      │
│ create                                                                                           │
│                                                                                                  │
│   35 │   │   │                                                                                   │
│   36 │   │   │   app.abort(f'Environment `{env}` is incompatible: {e}')                          │
│   37 │   │                                                                                       │
│ ❱ 38 │   │   app.prepare_environment(environment)                                                │
│   39 │                                                                                           │
│   40 │   if incompatible:                                                                        │
│   41 │   │   num_incompatible = len(incompatible)                                                │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\cli\application.py:89 in     │
│ prepare_environment                                                                              │
│                                                                                                  │
│    86 │   │   │   self.env_metadata.reset(environment)                                           │
│    87 │   │   │                                                                                  │
│    88 │   │   │   with self.status(f'Creating environment: {environment.name}'):                 │
│ ❱  89 │   │   │   │   environment.create()                                                       │
│    90 │   │   │                                                                                  │
│    91 │   │   │   if not environment.skip_install:                                               │
│    92 │   │   │   │   if environment.pre_install_commands:                                       │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\env\virtual.py:103 in create │
│                                                                                                  │
│   100 """                                                                                        │
│   101 │   │   │   │   )                                                                          │
│   102 │   │                                                                                      │
│ ❱ 103 │   │   self.virtual_env.create(self.parent_python, allow_system_packages=self.config.ge   │
│   104 │                                                                                          │
│   105 │   def remove(self):                                                                      │
│   106 │   │   self.virtual_env.remove()                                                          │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\venv\core.py:59 in create    │
│                                                                                                  │
│    56 │   │   # Decrease verbosity since the virtualenv CLI defaults to something like +2 verb   │
│    57 │   │   add_verbosity_flag(command, self.verbosity, adjustment=-1)                         │
│    58 │   │                                                                                      │
│ ❱  59 │   │   cli_run(command)                                                                   │
│    60 │                                                                                          │
│    61 │   def remove(self):                                                                      │
│    62 │   │   self.directory.remove()                                                            │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\run\__init__.py:33 in   │
│ cli_run                                                                                          │
│                                                                                                  │
│    30 │   env = os.environ if env is None else env                                               │
│    31 │   of_session = session_via_cli(args, options, setup_logging, env)                        │
│    32 │   with of_session:                                                                       │
│ ❱  33 │   │   of_session.run()                                                                   │
│    34 │   return of_session                                                                      │
│    35                                                                                            │
│    36                                                                                            │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\run\session.py:46 in    │
│ run                                                                                              │
│                                                                                                  │
│   43 │   def run(self):                                                                          │
│   44 │   │   self._create()                                                                      │
│   45 │   │   self._seed()                                                                        │
│ ❱ 46 │   │   self._activate()                                                                    │
│   47 │   │   self.creator.pyenv_cfg.write()                                                      │
│   48 │                                                                                           │
│   49 │   def _create(self):                                                                      │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\run\session.py:65 in    │
│ _activate                                                                                        │
│                                                                                                  │
│   62 │   │   │   active = ", ".join(type(i).__name__.replace("Activator", "") for i in self.a    │
│   63 │   │   │   logging.info("add activators for %s", active)                                   │
│   64 │   │   │   for activator in self.activators:                                               │
│ ❱ 65 │   │   │   │   activator.generate(self.creator)                                            │
│   66 │                                                                                           │
│   67 │   def __enter__(self):                                                                    │
│   68 │   │   return self                                                                         │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\activation\via_template │
│ .py:27 in generate                                                                               │
│                                                                                                  │
│   24 │   def generate(self, creator):                                                            │
│   25 │   │   dest_folder = creator.bin_dir                                                       │
│   26 │   │   replacements = self.replacements(creator, dest_folder)                              │
│ ❱ 27 │   │   generated = self._generate(replacements, self.templates(), dest_folder, creator)    │
│   28 │   │   if self.flag_prompt is not None:                                                    │
│   29 │   │   │   creator.pyenv_cfg["prompt"] = self.flag_prompt                                  │
│   30 │   │   return generated                                                                    │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\activation\via_template │
│ .py:51 in _generate                                                                              │
│                                                                                                  │
│   48 │   │   │   if dest.exists():                                                               │
│   49 │   │   │   │   dest.unlink()                                                               │
│   50 │   │   │   # Powershell assumes Windows 1252 encoding when reading files without BOM       │
│ ❱ 51 │   │   │   encoding = "utf-8-sig" if template.endswith(".ps1") else "utf-8"                │
│   52 │   │   │   # use write_bytes to avoid platform specific line normalization (\n -> \r\n)    │
│   53 │   │   │   dest.write_bytes(text.encode(encoding))                                         │
│   54 │   │   │   generated.append(dest)                                                          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
AttributeError: 'WindowsPath' object has no attribute 'endswith'
ofek commented 3 months ago

Can you modify this line in your installation by wrapping the first argument in str(...)?

balthild commented 3 months ago

No, it still raises the exception.

D:\Projects\Python\myproject via 🐍 v3.12.1
❯ hatch env create
╭─────────────────────────────── Traceback (most recent call last) ────────────────────────────────╮
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\cli\__init__.py:221 in main  │
│                                                                                                  │
│   218                                                                                            │
│   219 def main():  # no cov                                                                      │
│   220 │   try:                                                                                   │
│ ❱ 221 │   │   return hatch(prog_name='hatch', windows_expand_args=False)                         │
│   222 │   except Exception:  # noqa: BLE001                                                      │
│   223 │   │   from rich.console import Console                                                   │
│   224                                                                                            │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1157 in __call__     │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1078 in main         │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1688 in invoke       │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1688 in invoke       │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:1434 in invoke       │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\core.py:783 in invoke        │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\click\decorators.py:45 in new_func │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\cli\env\create.py:38 in      │
│ create                                                                                           │
│                                                                                                  │
│   35 │   │   │                                                                                   │
│   36 │   │   │   app.abort(f'Environment `{env}` is incompatible: {e}')                          │
│   37 │   │                                                                                       │
│ ❱ 38 │   │   app.prepare_environment(environment)                                                │
│   39 │                                                                                           │
│   40 │   if incompatible:                                                                        │
│   41 │   │   num_incompatible = len(incompatible)                                                │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\cli\application.py:89 in     │
│ prepare_environment                                                                              │
│                                                                                                  │
│    86 │   │   │   self.env_metadata.reset(environment)                                           │
│    87 │   │   │                                                                                  │
│    88 │   │   │   with self.status(f'Creating environment: {environment.name}'):                 │
│ ❱  89 │   │   │   │   environment.create()                                                       │
│    90 │   │   │                                                                                  │
│    91 │   │   │   if not environment.skip_install:                                               │
│    92 │   │   │   │   if environment.pre_install_commands:                                       │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\env\virtual.py:103 in create │
│                                                                                                  │
│   100 """                                                                                        │
│   101 │   │   │   │   )                                                                          │
│   102 │   │                                                                                      │
│ ❱ 103 │   │   self.virtual_env.create(str(self.parent_python), allow_system_packages=self.conf   │
│   104 │                                                                                          │
│   105 │   def remove(self):                                                                      │
│   106 │   │   self.virtual_env.remove()                                                          │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\hatch\venv\core.py:59 in create    │
│                                                                                                  │
│    56 │   │   # Decrease verbosity since the virtualenv CLI defaults to something like +2 verb   │
│    57 │   │   add_verbosity_flag(command, self.verbosity, adjustment=-1)                         │
│    58 │   │                                                                                      │
│ ❱  59 │   │   cli_run(command)                                                                   │
│    60 │                                                                                          │
│    61 │   def remove(self):                                                                      │
│    62 │   │   self.directory.remove()                                                            │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\run\__init__.py:33 in   │
│ cli_run                                                                                          │
│                                                                                                  │
│    30 │   env = os.environ if env is None else env                                               │
│    31 │   of_session = session_via_cli(args, options, setup_logging, env)                        │
│    32 │   with of_session:                                                                       │
│ ❱  33 │   │   of_session.run()                                                                   │
│    34 │   return of_session                                                                      │
│    35                                                                                            │
│    36                                                                                            │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\run\session.py:46 in    │
│ run                                                                                              │
│                                                                                                  │
│   43 │   def run(self):                                                                          │
│   44 │   │   self._create()                                                                      │
│   45 │   │   self._seed()                                                                        │
│ ❱ 46 │   │   self._activate()                                                                    │
│   47 │   │   self.creator.pyenv_cfg.write()                                                      │
│   48 │                                                                                           │
│   49 │   def _create(self):                                                                      │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\run\session.py:65 in    │
│ _activate                                                                                        │
│                                                                                                  │
│   62 │   │   │   active = ", ".join(type(i).__name__.replace("Activator", "") for i in self.a    │
│   63 │   │   │   logging.info("add activators for %s", active)                                   │
│   64 │   │   │   for activator in self.activators:                                               │
│ ❱ 65 │   │   │   │   activator.generate(self.creator)                                            │
│   66 │                                                                                           │
│   67 │   def __enter__(self):                                                                    │
│   68 │   │   return self                                                                         │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\activation\via_template │
│ .py:27 in generate                                                                               │
│                                                                                                  │
│   24 │   def generate(self, creator):                                                            │
│   25 │   │   dest_folder = creator.bin_dir                                                       │
│   26 │   │   replacements = self.replacements(creator, dest_folder)                              │
│ ❱ 27 │   │   generated = self._generate(replacements, self.templates(), dest_folder, creator)    │
│   28 │   │   if self.flag_prompt is not None:                                                    │
│   29 │   │   │   creator.pyenv_cfg["prompt"] = self.flag_prompt                                  │
│   30 │   │   return generated                                                                    │
│                                                                                                  │
│ C:\Users\Balthild\scoop\apps\python\current\Lib\site-packages\virtualenv\activation\via_template │
│ .py:51 in _generate                                                                              │
│                                                                                                  │
│   48 │   │   │   if dest.exists():                                                               │
│   49 │   │   │   │   dest.unlink()                                                               │
│   50 │   │   │   # Powershell assumes Windows 1252 encoding when reading files without BOM       │
│ ❱ 51 │   │   │   encoding = "utf-8-sig" if template.endswith(".ps1") else "utf-8"                │
│   52 │   │   │   # use write_bytes to avoid platform specific line normalization (\n -> \r\n)    │
│   53 │   │   │   dest.write_bytes(text.encode(encoding))                                         │
│   54 │   │   │   generated.append(dest)                                                          │
╰──────────────────────────────────────────────────────────────────────────────────────────────────╯
AttributeError: 'WindowsPath' object has no attribute 'endswith'
ofek commented 3 months ago

Yeah this would be an issue with virtualenv then. Although I would say before you open an issue there and close the one here, please try a different installation mechanism as I am wondering if that for some reason is influential.

balthild commented 3 months ago

Thank you! I'll have a try.

ofek commented 3 months ago

Please cross-link the other issue here so I know what ends up happening!