`sysconfig.get_path("purelib")` returns `site-packages` folder instead of `app_packages`
- Dominant language
- Python
- Stars
- 3.3k
- Forks
- 549
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 40
Description
### Describe the bug
`sysconfig.get_path("purelib")` returns `site-packages` folder instead of `app_packages`
Some libraries access `sysconfig.get_path("purelib")` to get the path of the folder, where the 3rd party libraries are installed. E.g. pydevd ([see here](https://github.com/fabioz/PyDev.Debugger/blob/3030fa9908187513bdd3e3dd93bfa897a95a6ece/pydevd_file_utils.py#L80)) or debugpy ([see here](https://github.com/microsoft/debugpy/blob/b00a8129977494bd127dd0bfed22082597762a08/src/debugpy/_vendored/pydevd/pydevd_file_utils.py#L80))
Currently `sysconfig.get_paths()` returns on Windows
```
{
'stdlib': '...\build\helloworld\windows\app\src\Lib',
'platstdlib': '...\build\helloworld\windows\app\src\Lib',
'purelib': '...\build\helloworld\windows\app\src\Lib\site-packages',
'platlib': '...\build\helloworld\windows\app\src\Lib\site-packages',
'include': '...\build\helloworld\windows\app\src\Include',
'platinclude': '...\build\helloworld\windows\app\src\Include',
'scripts': '...\build\helloworld\windows\app\src\Scripts',
'data': '...\build\helloworld\windows\app\src'
}
```
But `...\build\helloworld\windows\app\src\Lib\site-packages` does not exists, because all libraries are inside `...\build\helloworld\windows\app\src\app_packages`.
### Steps to reproduce
1. Create an example briefcase app
2. Add
```
import sysconfig
print(sysconfig.get_path("purelib"))
```
3. Run `briefcase run`
### Expected behavior
`sysconfig.get_path("purelib")` should return the path to the `app_packages` folder instead of the non existing `site-packages` folder.
### Screenshots
_No response_
### Environment
- Operating System: Windows 11
- Python version: 3.13
- Software versions:
- Briefcase: 0.3.24
### Logs
```
```
### Additional context
There has already been discussion about whether it makes sense to use the standard `site-packages` folder instead of a custom `app_packages` folder, and why it was rejected: https://github.com/beeware/briefcase/issues/2195
I created a working `sysconfig` patch function that can may be used:
```python
def _patch_sysconfig():
import sysconfig
BRIEFCASE_SCHEME = "briefcase"
sysconfig._INSTALL_SCHEMES[BRIEFCASE_SCHEME] = {
"stdlib": "{installed_base}/Lib",
"platstdlib": "{base}/Lib",
"purelib": "{base}/app_packages",
"platlib": "{base}/app_packages",
"include": "{installed_base}/Include",
"platinclude": "{installed_base}/Include",
"scripts": "{base}/Scripts",
"data": "{base}",
}
__orig_get_paths = sysconfig.get_paths
__orig_get_path = sysconfig.get_path
def get_default_scheme():
return BRIEFCASE_SCHEME
def get_paths(*args, **kwargs):
if len(args) >= 1:
new_args = list(args)
if new_args[0] is None:
new_args[0] = BRIEFCASE_SCHEME
args = tuple(new_args)
elif "scheme" not in kwargs or kwargs.get("scheme") is None:
kwargs["scheme"] = BRIEFCASE_SCHEME
return __orig_get_paths(*args, **kwargs)
def get_path(*args, **kwargs):
if len(args) >= 2:
new_args = list(args)
if new_args[1] is None:
new_args[1] = BRIEFCASE_SCHEME
args = tuple(new_args)
elif "scheme" not in kwargs or kwargs.get("scheme") is None:
kwargs["scheme"] = BRIEFCASE_SCHEME
return __orig_get_path(*args, **kwargs)
sysconfig.get_default_scheme = get_default_scheme
sysconfig.get_paths = get_paths
sysconfig.get_path = get_path
```
Contributor guide
Research direction
No implementation file or test is named. Start with the Windows app startup path used by `briefcase run` and the `sysconfig.get_path("purelib")` reproduction, then trace how the app's installation scheme is selected. Done means `purelib` and `platlib` resolve to the existing `app_packages` directory and the behavior is covered for the reported Windows environment.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- build-system
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100