|
1 |
| -import glob |
2 |
| -import os |
| 1 | +import site |
| 2 | +import subprocess |
| 3 | +import sys |
3 | 4 |
|
4 |
| -import setuptools |
5 |
| -from setuptools import _normalization, _path, namespaces |
6 |
| -from setuptools.command.easy_install import easy_install |
| 5 | +from setuptools import Command |
| 6 | +from setuptools.warnings import SetuptoolsDeprecationWarning |
7 | 7 |
|
8 |
| -from ..unicode_utils import _read_utf8_with_fallback |
9 | 8 |
|
10 |
| -from distutils import log |
11 |
| -from distutils.errors import DistutilsOptionError |
12 |
| -from distutils.util import convert_path |
13 |
| - |
14 |
| - |
15 |
| -class develop(namespaces.DevelopInstaller, easy_install): |
| 9 | +class develop(Command): |
16 | 10 | """Set up package for development"""
|
17 | 11 |
|
18 |
| - description = "install package in 'development mode'" |
19 |
| - |
20 |
| - user_options = easy_install.user_options + [ |
21 |
| - ("uninstall", "u", "Uninstall this source package"), |
22 |
| - ("egg-path=", None, "Set the path to be used in the .egg-link file"), |
| 12 | + user_options = [ |
| 13 | + ("install-dir=", "d", "install package to DIR"), |
| 14 | + ('no-deps', 'N', "don't install dependencies"), |
| 15 | + ('user', None, f"install in user site-package '{site.USER_SITE}'"), |
| 16 | + ('prefix=', None, "installation prefix"), |
| 17 | + ("index-url=", "i", "base URL of Python Package Index"), |
| 18 | + ] |
| 19 | + boolean_options = [ |
| 20 | + 'no-deps', |
| 21 | + 'user', |
23 | 22 | ]
|
24 | 23 |
|
25 |
| - boolean_options = easy_install.boolean_options + ['uninstall'] |
26 |
| - |
27 |
| - command_consumes_arguments = False # override base |
| 24 | + install_dir = None |
| 25 | + no_deps = False |
| 26 | + user = False |
| 27 | + prefix = None |
| 28 | + index_url = None |
28 | 29 |
|
29 | 30 | def run(self):
|
30 |
| - if self.uninstall: |
31 |
| - self.multi_version = True |
32 |
| - self.uninstall_link() |
33 |
| - self.uninstall_namespaces() |
34 |
| - else: |
35 |
| - self.install_for_development() |
36 |
| - self.warn_deprecated_options() |
| 31 | + cmd = ( |
| 32 | + [sys.executable, '-m', 'pip', 'install', '-e', '.', '--use-pep517'] |
| 33 | + + ['--target', self.install_dir] * bool(self.install_dir) |
| 34 | + + ['--no-deps'] * self.no_deps |
| 35 | + + ['--user'] * self.user |
| 36 | + + ['--prefix', self.prefix] * bool(self.prefix) |
| 37 | + + ['--index-url', self.index_url] * bool(self.prefix) |
| 38 | + ) |
| 39 | + subprocess.check_call(cmd) |
37 | 40 |
|
38 | 41 | def initialize_options(self):
|
39 |
| - self.uninstall = None |
40 |
| - self.egg_path = None |
41 |
| - easy_install.initialize_options(self) |
42 |
| - self.setup_path = None |
43 |
| - self.always_copy_from = '.' # always copy eggs installed in curdir |
| 42 | + DevelopDeprecationWarning.emit() |
44 | 43 |
|
45 | 44 | def finalize_options(self) -> None:
|
46 |
| - import pkg_resources |
47 |
| - |
48 |
| - ei = self.get_finalized_command("egg_info") |
49 |
| - self.args = [ei.egg_name] |
50 |
| - |
51 |
| - easy_install.finalize_options(self) |
52 |
| - self.expand_basedirs() |
53 |
| - self.expand_dirs() |
54 |
| - # pick up setup-dir .egg files only: no .egg-info |
55 |
| - self.package_index.scan(glob.glob('*.egg')) |
56 |
| - |
57 |
| - egg_link_fn = ( |
58 |
| - _normalization.filename_component_broken(ei.egg_name) + '.egg-link' |
59 |
| - ) |
60 |
| - self.egg_link = os.path.join(self.install_dir, egg_link_fn) |
61 |
| - self.egg_base = ei.egg_base |
62 |
| - if self.egg_path is None: |
63 |
| - self.egg_path = os.path.abspath(ei.egg_base) |
64 |
| - |
65 |
| - target = _path.normpath(self.egg_base) |
66 |
| - egg_path = _path.normpath(os.path.join(self.install_dir, self.egg_path)) |
67 |
| - if egg_path != target: |
68 |
| - raise DistutilsOptionError( |
69 |
| - "--egg-path must be a relative path from the install" |
70 |
| - " directory to " + target |
71 |
| - ) |
72 |
| - |
73 |
| - # Make a distribution for the package's source |
74 |
| - self.dist = pkg_resources.Distribution( |
75 |
| - target, |
76 |
| - pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)), |
77 |
| - project_name=ei.egg_name, |
78 |
| - ) |
79 |
| - |
80 |
| - self.setup_path = self._resolve_setup_path( |
81 |
| - self.egg_base, |
82 |
| - self.install_dir, |
83 |
| - self.egg_path, |
84 |
| - ) |
85 |
| - |
86 |
| - @staticmethod |
87 |
| - def _resolve_setup_path(egg_base, install_dir, egg_path): |
88 |
| - """ |
89 |
| - Generate a path from egg_base back to '.' where the |
90 |
| - setup script resides and ensure that path points to the |
91 |
| - setup path from $install_dir/$egg_path. |
92 |
| - """ |
93 |
| - path_to_setup = egg_base.replace(os.sep, '/').rstrip('/') |
94 |
| - if path_to_setup != os.curdir: |
95 |
| - path_to_setup = '../' * (path_to_setup.count('/') + 1) |
96 |
| - resolved = _path.normpath(os.path.join(install_dir, egg_path, path_to_setup)) |
97 |
| - curdir = _path.normpath(os.curdir) |
98 |
| - if resolved != curdir: |
99 |
| - raise DistutilsOptionError( |
100 |
| - "Can't get a consistent path to setup script from" |
101 |
| - " installation directory", |
102 |
| - resolved, |
103 |
| - curdir, |
104 |
| - ) |
105 |
| - return path_to_setup |
106 |
| - |
107 |
| - def install_for_development(self) -> None: |
108 |
| - self.run_command('egg_info') |
109 |
| - |
110 |
| - # Build extensions in-place |
111 |
| - self.reinitialize_command('build_ext', inplace=True) |
112 |
| - self.run_command('build_ext') |
| 45 | + pass |
113 | 46 |
|
114 |
| - if setuptools.bootstrap_install_from: |
115 |
| - self.easy_install(setuptools.bootstrap_install_from) |
116 |
| - setuptools.bootstrap_install_from = None |
117 | 47 |
|
118 |
| - self.install_namespaces() |
119 |
| - |
120 |
| - # create an .egg-link in the installation dir, pointing to our egg |
121 |
| - log.info("Creating %s (link to %s)", self.egg_link, self.egg_base) |
122 |
| - if not self.dry_run: |
123 |
| - with open(self.egg_link, "w", encoding="utf-8") as f: |
124 |
| - f.write(self.egg_path + "\n" + self.setup_path) |
125 |
| - # postprocess the installed distro, fixing up .pth, installing scripts, |
126 |
| - # and handling requirements |
127 |
| - self.process_distribution(None, self.dist, not self.no_deps) |
128 |
| - |
129 |
| - def uninstall_link(self) -> None: |
130 |
| - if os.path.exists(self.egg_link): |
131 |
| - log.info("Removing %s (link to %s)", self.egg_link, self.egg_base) |
132 |
| - |
133 |
| - contents = [ |
134 |
| - line.rstrip() |
135 |
| - for line in _read_utf8_with_fallback(self.egg_link).splitlines() |
136 |
| - ] |
137 |
| - |
138 |
| - if contents not in ([self.egg_path], [self.egg_path, self.setup_path]): |
139 |
| - log.warn("Link points to %s: uninstall aborted", contents) |
140 |
| - return |
141 |
| - if not self.dry_run: |
142 |
| - os.unlink(self.egg_link) |
143 |
| - if not self.dry_run: |
144 |
| - self.update_pth(self.dist) # remove any .pth link to us |
145 |
| - if self.distribution.scripts: |
146 |
| - # XXX should also check for entry point scripts! |
147 |
| - log.warn("Note: you must uninstall or replace scripts manually!") |
148 |
| - |
149 |
| - def install_egg_scripts(self, dist): |
150 |
| - if dist is not self.dist: |
151 |
| - # Installing a dependency, so fall back to normal behavior |
152 |
| - return easy_install.install_egg_scripts(self, dist) |
153 |
| - |
154 |
| - # create wrapper scripts in the script dir, pointing to dist.scripts |
155 |
| - |
156 |
| - # new-style... |
157 |
| - self.install_wrapper_scripts(dist) |
158 |
| - |
159 |
| - # ...and old-style |
160 |
| - for script_name in self.distribution.scripts or []: |
161 |
| - script_path = os.path.abspath(convert_path(script_name)) |
162 |
| - script_name = os.path.basename(script_path) |
163 |
| - script_text = _read_utf8_with_fallback(script_path) |
164 |
| - self.install_script(dist, script_name, script_text, script_path) |
165 |
| - |
166 |
| - return None |
167 |
| - |
168 |
| - def install_wrapper_scripts(self, dist): |
169 |
| - dist = VersionlessRequirement(dist) |
170 |
| - return easy_install.install_wrapper_scripts(self, dist) |
171 |
| - |
172 |
| - |
173 |
| -class VersionlessRequirement: |
174 |
| - """ |
175 |
| - Adapt a pkg_resources.Distribution to simply return the project |
176 |
| - name as the 'requirement' so that scripts will work across |
177 |
| - multiple versions. |
178 |
| -
|
179 |
| - >>> from pkg_resources import Distribution |
180 |
| - >>> dist = Distribution(project_name='foo', version='1.0') |
181 |
| - >>> str(dist.as_requirement()) |
182 |
| - 'foo==1.0' |
183 |
| - >>> adapted_dist = VersionlessRequirement(dist) |
184 |
| - >>> str(adapted_dist.as_requirement()) |
185 |
| - 'foo' |
| 48 | +class DevelopDeprecationWarning(SetuptoolsDeprecationWarning): |
| 49 | + _SUMMARY = "develop command is deprecated." |
| 50 | + _DETAILS = """ |
| 51 | + Please avoid running ``setup.py`` and ``develop``. |
| 52 | + Instead, use standards-based tools like pip or uv. |
186 | 53 | """
|
187 |
| - |
188 |
| - def __init__(self, dist) -> None: |
189 |
| - self.__dist = dist |
190 |
| - |
191 |
| - def __getattr__(self, name: str): |
192 |
| - return getattr(self.__dist, name) |
193 |
| - |
194 |
| - def as_requirement(self): |
195 |
| - return self.project_name |
| 54 | + _SEE_URL = "https://github.com/pypa/setuptools/issues/917" |
| 55 | + _DUE_DATE = 2025, 10, 31 |
0 commit comments