Repository: pypa/setuptools

Issue:
easy_install doesn't handle sysconfig vars being integers.
In the `create_home_path` function of `setuptools/command/easy_install.py` the code fails with an AttributeError if `path` is not a string. Since #3027 `self.config_vars` has been created from `sysconfig.get_config_vars()`, where the values can be strings or integers, such as `'WITH_PYMALLOC': 1`.

https://github.com/pypa/setuptools/blob/b2ba0e39918d58bd6c6b15093ddcdc42605040ce/setuptools/command/easy_install.py#L241

https://github.com/pypa/setuptools/blob/b2ba0e39918d58bd6c6b15093ddcdc42605040ce/setuptools/command/easy_install.py#L1337-L1338

Because integers do not have a `startswith` method an AttributeError is raised. Checking whether `path` is a string should fix this.

I tried to reproduce this locally with `easy_install`, but couldn't. However, it can be observed in pip's testsuite: https://github.com/pypa/pip/runs/5002678226



Discussion:
We are also seeing this issue where `path` seems to be an `int` (not sure how that can happen in the first place). This is breaking our CICD pipelines. For now, we will add `<=0.60.5`, but let us know when this is fixed!
Ran into this issue trying to`pip install -e .` a module locally:

```
 $ pip list | grep -E 'setuptools|pip'
pip                      22.0.2
setuptools               60.6.0
```

```
$ pip install --editable .
Defaulting to user installation because normal site-packages is not writeable
Obtaining file:///home/sean/Repos/sqlite_backup
  Preparing metadata (setup.py): started
  Preparing metadata (setup.py): finished with status 'done'
Requirement already satisfied: click>=7.0 in /usr/lib/python3.10/site-packages (from sqlite-backup==0.1.0) (8.0.3)
Installing collected packages: sqlite-backup
  Attempting uninstall: sqlite-backup
    Found existing installation: sqlite-backup 0.1.0
    Uninstalling sqlite-backup-0.1.0:
      Successfully uninstalled sqlite-backup-0.1.0
  Running setup.py develop for sqlite-backup
    error: subprocess-exited-with-error
    
    × python setup.py develop did not run successfully.
    │ exit code: 1
    ╰─> [29 lines of output]
        running develop
        /home/sean/.local/lib/python3.10/site-packages/setuptools/command/easy_install.py:157: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.
          warnings.warn(
        Traceback (most recent call last):
          File "<string>", line 2, in <module>
          File "<pip-setuptools-caller>", line 34, in <module>
          File "/home/sean/Repos/sqlite_backup/setup.py", line 8, in <module>
            setup(
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/__init__.py", line 155, in setup
            return distutils.core.setup(**attrs)
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/core.py", line 148, in setup
            return run_commands(dist)
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/core.py", line 163, in run_commands
            dist.run_commands()
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/dist.py", line 967, in run_commands
            self.run_command(cmd)
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/dist.py", line 985, in run_command
            cmd_obj.ensure_finalized()
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/cmd.py", line 107, in ensure_finalized
            self.finalize_options()
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/command/develop.py", line 52, in finalize_options
            easy_install.finalize_options(self)
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/command/easy_install.py", line 276, in finalize_options
            self._fix_install_dir_for_user_site()
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/command/easy_install.py", line 382, in _fix_install_dir_for_user_site
            self.create_home_path()
          File "/home/sean/.local/lib/python3.10/site-packages/setuptools/command/easy_install.py", line 1338, in create_home_path
            if path.startswith(home) and not os.path.isdir(path):
        AttributeError: 'int' object has no attribute 'startswith'
        [end of output]
    
    note: This error originates from a subprocess, and is likely not a problem with pip.
  WARNING: No metadata found in /home/sean/.local/lib/python3.10/site-packages
  Rolling back uninstall of sqlite-backup
  Moving to /home/sean/.local/bin/sqlite_backup
   from /tmp/pip-uninstall-q7xp83v5/sqlite_backup
  Moving to /home/sean/.local/lib/python3.10/site-packages/sqlite_backup-0.1.0.dist-info/
   from /home/sean/.local/lib/python3.10/site-packages/~qlite_backup-0.1.0.dist-info
  Moving to /home/sean/.local/lib/python3.10/site-packages/sqlite_backup/
   from /home/sean/.local/lib/python3.10/site-packages/~qlite_backup
error: subprocess-exited-with-error

× python setup.py develop did not run successfully.
│ exit code: 1
╰─> [29 lines of output]
    running develop
    /home/sean/.local/lib/python3.10/site-packages/setuptools/command/easy_install.py:157: EasyInstallDeprecationWarning: easy_install command is deprecated. Use build and pip and other standards-based tools.
      warnings.warn(
    Traceback (most recent call last):
      File "<string>", line 2, in <module>
      File "<pip-setuptools-caller>", line 34, in <module>
      File "/home/sean/Repos/sqlite_backup/setup.py", line 8, in <module>
        setup(
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/__init__.py", line 155, in setup
        return distutils.core.setup(**attrs)
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/core.py", line 148, in setup
        return run_commands(dist)
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/core.py", line 163, in run_commands
        dist.run_commands()
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/dist.py", line 967, in run_commands
        self.run_command(cmd)
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/dist.py", line 985, in run_command
        cmd_obj.ensure_finalized()
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/_distutils/cmd.py", line 107, in ensure_finalized
        self.finalize_options()
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/command/develop.py", line 52, in finalize_options
        easy_install.finalize_options(self)
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/command/easy_install.py", line 276, in finalize_options
        self._fix_install_dir_for_user_site()
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/command/easy_install.py", line 382, in _fix_install_dir_for_user_site
        self.create_home_path()
      File "/home/sean/.local/lib/python3.10/site-packages/setuptools/command/easy_install.py", line 1338, in create_home_path
        if path.startswith(home) and not os.path.isdir(path):
    AttributeError: 'int' object has no attribute 'startswith'
    [end of output]

note: This error originates from a subprocess, and is likely not a problem with pip.
```

I get the same error running `python3 setup.py develop --user`, with [this setup.py](https://github.com/seanbreckenridge/sqlite_backup/blob/master/setup.py)

Found a temporary solution for this while still on `60.6.0` [here](https://github.com/jupyter-widgets/ipywidgets/pull/3360), by specifying the `--prefix` -- Both

- `pip install --prefix=$(python -m site --user-base) --editable .`
- `python setup.py develop --prefix=$(python -m site --user-base)`

seem to work
@seanbreckenridge  thank you so much for the workaround!!! I was going crazy for hours yesterday because of this bug. I was also able to now install two packages I needed. On Ubuntu 20.04, used `pip3 install --prefix=$(python3 -m site --user-base) --editable.` The relevant error to help people find this is
```
File "/home/<user>/.local/lib/python3.8/site-packages/setuptools/command/easy_install.py", line 1338, in create_home_path
        if path.startswith(home) and not os.path.isdir(path):
    AttributeError: 'int' object has no attribute 'startswith'
```
Tried with both pip 20.0.2 and 22.0.2.
Hi @domdfcoding, thank you very much for finding this out and for the extensive investigation!

Any chance you can help us out with a PR? 😝 

Resolving patch:
diff --git a/setuptools/command/easy_install.py b/setuptools/command/easy_install.py
--- a/setuptools/command/easy_install.py
+++ b/setuptools/command/easy_install.py
@@ -1334,7 +1334,7 @@ def create_home_path(self):
         if not self.user:
             return
         home = convert_path(os.path.expanduser("~"))
-        for name, path in self.config_vars.items():
+        for path in only_strs(self.config_vars.values()):
             if path.startswith(home) and not os.path.isdir(path):
                 self.debug_print("os.makedirs('%s', 0o700)" % path)
                 os.makedirs(path, 0o700)
@@ -2304,6 +2304,13 @@ def current_umask():
     return tmp
 
 
+def only_strs(values):
+    """
+    Exclude non-str values. Ref #3063.
+    """
+    return filter(lambda val: isinstance(val, str), values)
+
+
 class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
     """
     Warning for EasyInstall deprecations, bypassing suppression.


Test patch: