dotslash 0.5.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,6 @@
1
+ # https://developers.google.com/gemini-code-assist/docs/customize-gemini-behavior-github
2
+ have_fun: false
3
+ code_review:
4
+ pull_request_opened:
5
+ summary: false
6
+ code_review: false
@@ -0,0 +1,2 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
@@ -0,0 +1,112 @@
1
+ name: build
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - v*
7
+ branches:
8
+ - main
9
+ pull_request:
10
+ branches:
11
+ - main
12
+
13
+ concurrency:
14
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
15
+ cancel-in-progress: true
16
+
17
+ defaults:
18
+ run:
19
+ shell: bash
20
+
21
+ jobs:
22
+ sdist:
23
+ name: Build source distribution
24
+ runs-on: ubuntu-latest
25
+
26
+ outputs:
27
+ dotslash-version: ${{ steps.dotslash-version.outputs.dotslash-version }}
28
+
29
+ steps:
30
+ - uses: actions/checkout@v5
31
+
32
+ - name: Set DotSlash version
33
+ id: dotslash-version
34
+ run: |-
35
+ dotslash_version=$(gh api repos/facebook/dotslash/releases/latest --jq '.tag_name')
36
+ echo "dotslash-version=${dotslash_version}" >> $GITHUB_OUTPUT
37
+ env:
38
+ GH_TOKEN: ${{ github.token }}
39
+
40
+ - name: Install uv
41
+ uses: astral-sh/setup-uv@v6
42
+
43
+ - name: Build source distribution
44
+ run: uv build --sdist
45
+ env:
46
+ DOTSLASH_VERSION: ${{ steps.dotslash-version.outputs.dotslash-version }}
47
+
48
+ - uses: actions/upload-artifact@v4
49
+ with:
50
+ name: artifact-sdist
51
+ path: dist/*
52
+ if-no-files-found: error
53
+
54
+ wheels:
55
+ name: Build wheels on ${{ matrix.os }}
56
+ needs:
57
+ - sdist
58
+ runs-on: ${{ matrix.os }}
59
+ strategy:
60
+ fail-fast: false
61
+ matrix:
62
+ include:
63
+ - os: ubuntu-24.04-arm
64
+ archs: aarch64
65
+ - os: ubuntu-latest
66
+ archs: x86_64
67
+ - os: macos-latest
68
+ archs: arm64
69
+ - os: macos-15-intel
70
+ archs: x86_64
71
+ - os: windows-11-arm
72
+ archs: ARM64
73
+ - os: windows-latest
74
+ archs: AMD64
75
+
76
+ steps:
77
+ - uses: actions/checkout@v5
78
+
79
+ - name: Build wheels
80
+ uses: pypa/cibuildwheel@v3.2.1
81
+ env:
82
+ DOTSLASH_VERSION: ${{ needs.sdist.outputs.dotslash-version }}
83
+ CIBW_ARCHS: ${{ matrix.archs }}
84
+
85
+ - uses: actions/upload-artifact@v4
86
+ with:
87
+ name: artifact-wheels-${{ matrix.os }}-${{ matrix.archs }}
88
+ path: wheelhouse/*.whl
89
+ if-no-files-found: error
90
+
91
+ publish:
92
+ name: Publish release
93
+ needs:
94
+ - sdist
95
+ - wheels
96
+ runs-on: ubuntu-latest
97
+ if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags')
98
+
99
+ permissions:
100
+ id-token: write
101
+
102
+ steps:
103
+ - uses: actions/download-artifact@v4
104
+ with:
105
+ pattern: artifact-*
106
+ merge-multiple: true
107
+ path: dist
108
+
109
+ - name: Push build artifacts to PyPI
110
+ uses: pypa/gh-action-pypi-publish@v1.13.0
111
+ with:
112
+ skip-existing: true
@@ -0,0 +1,34 @@
1
+ name: test
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+ pull_request:
8
+ branches:
9
+ - main
10
+
11
+ concurrency:
12
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
13
+ cancel-in-progress: true
14
+
15
+ defaults:
16
+ run:
17
+ shell: bash
18
+
19
+ jobs:
20
+ test:
21
+ name: Test
22
+ runs-on: ubuntu-latest
23
+
24
+ steps:
25
+ - uses: actions/checkout@v5
26
+
27
+ - name: Install uv
28
+ uses: astral-sh/setup-uv@v6
29
+
30
+ - name: Static analysis
31
+ run: uvx ruff check ./src
32
+
33
+ - name: Formatting
34
+ run: uvx ruff format --check --diff ./src
@@ -0,0 +1,2 @@
1
+ *.pyc
2
+ /dist
@@ -0,0 +1,61 @@
1
+ Metadata-Version: 2.4
2
+ Name: dotslash
3
+ Version: 0.5.8
4
+ Summary: Command-line tool to facilitate fetching an executable, caching it, and then running it.
5
+ Project-URL: Homepage, https://dotslash-cli.com
6
+ Project-URL: Tracker, https://github.com/facebook/dotslash/issues
7
+ Project-URL: Source, https://github.com/facebook/dotslash
8
+ Author-email: Ofek Lev <oss@ofek.dev>
9
+ License-Expression: MIT OR Apache-2.0
10
+ Keywords: dotslash
11
+ Classifier: Development Status :: 5 - Production/Stable
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Natural Language :: English
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: Implementation :: CPython
16
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+
20
+ # DotSlash: simplified executable deployment
21
+
22
+ [![CI - Build](https://github.com/ofek/dotslash/actions/workflows/build.yml/badge.svg)](https://github.com/ofek/dotslash/actions/workflows/build.yml)
23
+ [![CI - Test](https://github.com/ofek/dotslash/actions/workflows/test.yml/badge.svg)](https://github.com/ofek/dotslash/actions/workflows/test.yml)
24
+ [![PyPI - Version](https://img.shields.io/pypi/v/dotslash.svg?logo=pypi&label=PyPI&logoColor=gold)](https://pypi.org/project/dotslash/)
25
+ [![PyPI - Downloads](https://img.shields.io/pypi/dm/dotslash.svg?color=blue&label=Downloads&logo=pypi&logoColor=gold)](https://pypi.org/project/dotslash/)
26
+ [![Built by Hatch](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
27
+ [![Ruff linting/formatting](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
28
+
29
+ -----
30
+
31
+ [DotSlash](https://dotslash-cli.com/docs/) (`dotslash`) is a command-line tool that lets you represent a set of platform-specific, heavyweight executables with an equivalent small, easy-to-read text file. In turn, this makes it efficient to store executables in source control without hurting repository size. This paves the way for checking build toolchains and other tools directly into the repo, reducing dependencies on the host environment and thereby facilitating reproducible builds.
32
+
33
+ The `dotslash` package allows you to use DotSlash in your Python projects without having to install DotSlash globally.
34
+
35
+ ***Table of Contents***
36
+
37
+ - [Using as a library](#using-as-a-library)
38
+ - [Using as a command-line tool](#using-as-a-command-line-tool)
39
+ - [License](#license)
40
+
41
+ ## Using as a library
42
+
43
+ The `dotslash.locate` function returns the path to the DotSlash binary that was installed by this package.
44
+
45
+ ```pycon
46
+ >>> import dotslash
47
+ >>> dotslash.locate()
48
+ '/root/.local/bin/dotslash'
49
+ ```
50
+
51
+ ## Using as a command-line tool
52
+
53
+ The installed DotSlash binary can be invoked directly by running the `dotslash` module as a script.
54
+
55
+ ```
56
+ python -m dotslash path/to/dotslash-file.json
57
+ ```
58
+
59
+ ## License
60
+
61
+ DotSlash is licensed under both the MIT license and Apache-2.0 license; the exact terms can be found in the [LICENSE-MIT]() and LICENSE-APACHE files, respectively.
@@ -0,0 +1,59 @@
1
+ # DotSlash: simplified executable deployment
2
+
3
+ [![CI - Build](https://github.com/ofek/dotslash/actions/workflows/build.yml/badge.svg)](https://github.com/ofek/dotslash/actions/workflows/build.yml)
4
+ [![CI - Test](https://github.com/ofek/dotslash/actions/workflows/test.yml/badge.svg)](https://github.com/ofek/dotslash/actions/workflows/test.yml)
5
+ [![PyPI - Version](https://img.shields.io/pypi/v/dotslash.svg?logo=pypi&label=PyPI&logoColor=gold)](https://pypi.org/project/dotslash/)
6
+ [![PyPI - Downloads](https://img.shields.io/pypi/dm/dotslash.svg?color=blue&label=Downloads&logo=pypi&logoColor=gold)](https://pypi.org/project/dotslash/)
7
+ [![Built by Hatch](https://img.shields.io/badge/%F0%9F%A5%9A-Hatch-4051b5.svg)](https://github.com/pypa/hatch)
8
+ [![Ruff linting/formatting](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
9
+
10
+ -----
11
+
12
+ [DotSlash](https://dotslash-cli.com/docs/) (`dotslash`) is a command-line tool that lets you represent a set of platform-specific, heavyweight executables with an equivalent small, easy-to-read text file. In turn, this makes it efficient to store executables in source control without hurting repository size. This paves the way for checking build toolchains and other tools directly into the repo, reducing dependencies on the host environment and thereby facilitating reproducible builds.
13
+
14
+ The `dotslash` package allows you to use DotSlash in your Python projects without having to install DotSlash globally.
15
+
16
+ ***Table of Contents***
17
+
18
+ - [Using as a library](#using-as-a-library)
19
+ - [Using as a command-line tool](#using-as-a-command-line-tool)
20
+ - [Building from source](#building-from-source)
21
+ - [License](#license)
22
+
23
+ ## Using as a library
24
+
25
+ The `dotslash.locate` function returns the path to the DotSlash binary that was installed by this package.
26
+
27
+ ```pycon
28
+ >>> import dotslash
29
+ >>> dotslash.locate()
30
+ '/root/.local/bin/dotslash'
31
+ ```
32
+
33
+ ## Using as a command-line tool
34
+
35
+ The installed DotSlash binary can be invoked directly by running the `dotslash` module as a script.
36
+
37
+ ```
38
+ python -m dotslash path/to/dotslash-file.json
39
+ ```
40
+
41
+ ## Building from source
42
+
43
+ When building or installing from this directory, the `DOTSLASH_VERSION` environment variable must be set to the version of DotSlash to use. A preceding `v` is accepted but not required.
44
+
45
+ ```
46
+ DOTSLASH_VERSION=0.5.8 python -m build
47
+ ```
48
+
49
+ This will use the binaries from DotSlash's [GitHub releases](https://github.com/facebook/dotslash/releases). If there is a directory of GitHub release assets, you can use that directly with the `DOTSLASH_SOURCE` environment variable.
50
+
51
+ ```
52
+ DOTSLASH_VERSION=0.5.8 DOTSLASH_SOURCE=path/to/dotslash-assets python -m build
53
+ ```
54
+
55
+ The DotSlash source is set to `release` by default.
56
+
57
+ ## License
58
+
59
+ DotSlash is licensed under both the MIT license and Apache-2.0 license; the exact terms can be found in the [LICENSE-MIT]() and LICENSE-APACHE files, respectively.
@@ -0,0 +1,152 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import sys
5
+ from contextlib import contextmanager
6
+ from functools import cached_property
7
+ from platform import machine
8
+ from typing import TYPE_CHECKING, Any, BinaryIO
9
+
10
+ from hatchling.builders.hooks.plugin.interface import BuildHookInterface
11
+
12
+ if TYPE_CHECKING:
13
+ from collections.abc import Generator
14
+
15
+
16
+ class CustomBuildHook(BuildHookInterface):
17
+ def initialize(self, version: str, build_data: dict[str, Any]) -> None: # noqa: ARG002
18
+ if self.__source == "release":
19
+ asset = self.__release_asset
20
+ elif os.path.isdir(self.__source):
21
+ asset = self.__local_asset
22
+ elif not os.path.isabs(self.__source) and os.path.isfile(os.path.join(self.root, "PKG-INFO")):
23
+ msg = (
24
+ "The current directory has a `PKG-INFO` file, which likely means that the wheel is being "
25
+ "built from an unpacked source distribution. You must do one of the following:\n"
26
+ "- Set the source to an absolute rather than relative path.\n"
27
+ "- Build the wheel separately e.g. run `python -m build --wheel` rather than just `python -m build`.\n"
28
+ "- Set the source to `release`."
29
+ )
30
+ raise ValueError(msg)
31
+ else:
32
+ msg = "Source must be `release` or an absolute path to a directory containing release assets"
33
+ raise ValueError(msg)
34
+
35
+ import tarfile
36
+
37
+ with asset() as reader, tarfile.open(fileobj=reader, mode="r:gz") as tf:
38
+ tf.extractall(self.__temp_dir)
39
+
40
+ if not os.path.isfile(self.__binary_path):
41
+ msg = f"Binary not found: {self.__binary_path}"
42
+ raise RuntimeError(msg)
43
+
44
+ build_data["shared_scripts"][self.__binary_path] = self.__binary_name
45
+ build_data["tag"] = f"py3-none-{self.__wheel_arch}"
46
+
47
+ def finalize(self, version: str, build_data: dict[str, Any], artifact: str) -> None: # noqa: ARG002
48
+ import shutil
49
+
50
+ shutil.rmtree(self.__temp_dir)
51
+
52
+ @contextmanager
53
+ def __release_asset(self) -> Generator[BinaryIO, None, None]:
54
+ from urllib.request import HTTPError, urlopen
55
+
56
+ tag = f"v{self.metadata.version.removeprefix('v')}"
57
+ url = f"https://github.com/facebook/dotslash/releases/download/{tag}/{self.__asset_name}"
58
+
59
+ try:
60
+ with urlopen(url) as response:
61
+ yield response
62
+ except HTTPError as e:
63
+ e.msg += f"\nURL: {url}"
64
+ raise
65
+
66
+ @contextmanager
67
+ def __local_asset(self) -> Generator[BinaryIO, None, None]:
68
+ asset_path = os.path.join(self.__source, self.__asset_name)
69
+ if not os.path.isfile(asset_path):
70
+ msg = f"Asset not found: {asset_path}"
71
+ raise RuntimeError(msg)
72
+
73
+ with open(asset_path, "rb") as f:
74
+ yield f
75
+
76
+ @cached_property
77
+ def __platform(self) -> str:
78
+ match sys.platform:
79
+ case "win32":
80
+ return "windows"
81
+ case "darwin":
82
+ return "macos"
83
+ case "linux":
84
+ return "linux"
85
+ case _:
86
+ msg = f"Unsupported platform: {sys.platform}"
87
+ raise ValueError(msg)
88
+
89
+ @cached_property
90
+ def __arch(self) -> str:
91
+ return machine().lower()
92
+
93
+ @cached_property
94
+ def __target_data(self) -> tuple[str, str]:
95
+ match self.__platform, self.__arch:
96
+ case "linux", "aarch64":
97
+ return "dotslash-linux-musl.aarch64.tar.gz", self.__get_linux_wheel_arch()
98
+ case "linux", "x86_64":
99
+ return "dotslash-linux-musl.x86_64.tar.gz", self.__get_linux_wheel_arch()
100
+ case "windows", "arm64":
101
+ return "dotslash-windows-arm64.tar.gz", "win_arm64"
102
+ case "windows", "amd64":
103
+ return "dotslash-windows.tar.gz", "win_amd64"
104
+ case "macos", "arm64":
105
+ return "dotslash-macos-arm64.tar.gz", "macosx_11_0_arm64"
106
+ case "macos", "x86_64":
107
+ return "dotslash-macos-x86_64.tar.gz", "macosx_10_12_x86_64"
108
+ case _:
109
+ msg = f"Unsupported platform/arch pair: {self.__platform} {self.__arch}"
110
+ raise ValueError(msg)
111
+
112
+ @cached_property
113
+ def __asset_name(self) -> str:
114
+ return self.__target_data[0]
115
+
116
+ @cached_property
117
+ def __wheel_arch(self) -> str:
118
+ return self.__target_data[1]
119
+
120
+ @cached_property
121
+ def __source(self) -> str:
122
+ return os.environ.get("DOTSLASH_SOURCE") or self.config.get("source") or "release"
123
+
124
+ @cached_property
125
+ def __temp_dir(self) -> str:
126
+ import tempfile
127
+
128
+ return tempfile.mkdtemp()
129
+
130
+ @cached_property
131
+ def __binary_name(self) -> str:
132
+ return "dotslash.exe" if self.__platform == "windows" else "dotslash"
133
+
134
+ @cached_property
135
+ def __binary_path(self) -> str:
136
+ return os.path.join(self.__temp_dir, self.__binary_name)
137
+
138
+ def __get_linux_wheel_arch(self) -> str:
139
+ default_arch = f"musllinux_1_1_{self.__arch}"
140
+
141
+ if not (hasattr(os, "confstr") and "CS_GNU_LIBC_VERSION" in os.confstr_names):
142
+ return default_arch
143
+
144
+ try:
145
+ value = os.confstr("CS_GNU_LIBC_VERSION")
146
+ except (OSError, ValueError):
147
+ pass
148
+ else:
149
+ if value and value.startswith("glibc"):
150
+ return f"manylinux_2_28_{self.__arch}"
151
+
152
+ return default_arch
@@ -0,0 +1,61 @@
1
+ [build-system]
2
+ build-backend = "hatchling.build"
3
+ requires = ["hatchling>=1.27.0", "hatch-fancy-pypi-readme"]
4
+
5
+ [project]
6
+ name = "dotslash"
7
+ dynamic = ["readme", "version"]
8
+ authors = [
9
+ { name = "Ofek Lev", email = "oss@ofek.dev" },
10
+ ]
11
+ description = "Command-line tool to facilitate fetching an executable, caching it, and then running it."
12
+ keywords = [
13
+ "dotslash",
14
+ ]
15
+ license = "MIT OR Apache-2.0"
16
+ requires-python = ">=3.10"
17
+ classifiers = [
18
+ "Development Status :: 5 - Production/Stable",
19
+ "Intended Audience :: Developers",
20
+ "Natural Language :: English",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: Implementation :: CPython",
23
+ "Programming Language :: Python :: Implementation :: PyPy",
24
+ ]
25
+
26
+ [project.urls]
27
+ Homepage = "https://dotslash-cli.com"
28
+ Tracker = "https://github.com/facebook/dotslash/issues"
29
+ Source = "https://github.com/facebook/dotslash"
30
+
31
+ [tool.hatch.version]
32
+ source = "env"
33
+ variable = "DOTSLASH_VERSION"
34
+
35
+ [tool.hatch.metadata.hooks.fancy-pypi-readme]
36
+ content-type = "text/markdown"
37
+
38
+ [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
39
+ path = "README.md"
40
+ end-before = "## Building from source"
41
+
42
+ [[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]]
43
+ path = "README.md"
44
+ start-at = "## License"
45
+
46
+ [[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]]
47
+ pattern = "(?m)^- \\[Building from source.+$\\s+-"
48
+ replacement = "-"
49
+
50
+ [tool.hatch.build.targets.wheel.hooks.custom]
51
+
52
+ [tool.cibuildwheel]
53
+ enable = ["pypy"]
54
+ test-command = "python -m dotslash -- cache-dir"
55
+ # Only build on one version of Python since all distributions of a given platform/arch pair are the same
56
+ build = "cp314-*"
57
+ # Disable wheel repair since it's not necessary
58
+ repair-wheel-command = ""
59
+
60
+ [tool.cibuildwheel.linux]
61
+ environment-pass = ["DOTSLASH_SOURCE", "DOTSLASH_VERSION"]
@@ -0,0 +1,11 @@
1
+ line-length = 120
2
+
3
+ [format]
4
+ docstring-code-format = true
5
+ docstring-code-line-length = 80
6
+
7
+ [lint.flake8-tidy-imports]
8
+ ban-relative-imports = "all"
9
+
10
+ [lint.isort]
11
+ known-first-party = ["dotslash"]
@@ -0,0 +1,36 @@
1
+ from __future__ import annotations
2
+
3
+
4
+ def locate() -> str:
5
+ """
6
+ Returns:
7
+ The path to the DotSlash binary that was installed by this package.
8
+ """
9
+ import os
10
+ import sys
11
+ import sysconfig
12
+
13
+ from dotslash._locate import _search_paths
14
+
15
+ if extension := sysconfig.get_config_var("EXE"):
16
+ binary_name = f"dotslash{extension}"
17
+ elif sys.platform == "win32":
18
+ binary_name = "dotslash.exe"
19
+ else:
20
+ binary_name = "dotslash"
21
+
22
+ # Map of normalized paths to the actual path
23
+ seen_paths: dict[str, str] = {}
24
+ for search_path in _search_paths():
25
+ normalized_path = os.path.normcase(search_path)
26
+ if normalized_path in seen_paths:
27
+ continue
28
+
29
+ seen_paths[normalized_path] = search_path
30
+ binary_path = os.path.join(search_path, binary_name)
31
+ if os.path.isfile(binary_path):
32
+ return binary_path
33
+
34
+ search_paths = "\n".join(f"- {search_path}" for search_path in seen_paths.values())
35
+ msg = f"The `{binary_name}` binary was not found in any of the following paths:\n{search_paths}"
36
+ raise FileNotFoundError(msg)
@@ -0,0 +1,16 @@
1
+ if __name__ == "__main__":
2
+ import sys
3
+
4
+ from dotslash import locate
5
+
6
+ dotslash = locate()
7
+
8
+ if sys.platform == "win32":
9
+ import subprocess
10
+
11
+ process = subprocess.run([dotslash, *sys.argv[1:]])
12
+ sys.exit(process.returncode)
13
+ else:
14
+ import os
15
+
16
+ os.execvp(dotslash, [dotslash, *sys.argv[1:]])
@@ -0,0 +1,39 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ import sys
5
+ import sysconfig
6
+
7
+
8
+ def _search_paths():
9
+ # The scripts directory for the current Python installation
10
+ yield sysconfig.get_path("scripts")
11
+
12
+ # The scripts directory for the base prefix if in a virtual environment
13
+ yield sysconfig.get_path("scripts", vars={"base": sys.base_prefix, "platbase": sys.base_exec_prefix})
14
+
15
+ module_dir = os.path.dirname(os.path.abspath(__file__))
16
+ package_parent, package_name = os.path.split(module_dir)
17
+ if package_name == "dotslash":
18
+ # Above the package root e.g. when running `pip install --prefix` or `uv run --with`
19
+ # Windows: <prefix>\Lib\site-packages\dotslash
20
+ # macOS: <prefix>/lib/pythonX.Y/site-packages/dotslash
21
+ # Linux:
22
+ # <prefix>/lib/pythonX.Y/site-packages/dotslash
23
+ # <prefix>/lib/pythonX.Y/dist-packages/dotslash (Debian-based distributions)
24
+ head, tail = os.path.split(package_parent)
25
+ if tail.endswith("-packages"):
26
+ head, tail = os.path.split(head)
27
+ if sys.platform == "win32":
28
+ if tail == "Lib":
29
+ yield os.path.join(head, "Scripts")
30
+ elif tail.startswith("python"):
31
+ head, tail = os.path.split(head)
32
+ if tail == sys.platlibdir:
33
+ yield os.path.join(head, "bin")
34
+ else:
35
+ # Adjacent to the package root e.g. when using the `--target` option of pip-like installers
36
+ yield os.path.join(package_parent, "bin")
37
+
38
+ # The scripts directory for user installations
39
+ yield sysconfig.get_path("scripts", scheme=sysconfig.get_preferred_scheme("user"))
File without changes