pip 25.1.1__py3-none-any.whl → 25.2__py3-none-any.whl

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.
Files changed (202) hide show
  1. pip/__init__.py +3 -3
  2. pip/_internal/__init__.py +2 -2
  3. pip/_internal/build_env.py +118 -94
  4. pip/_internal/cache.py +16 -14
  5. pip/_internal/cli/autocompletion.py +13 -4
  6. pip/_internal/cli/base_command.py +18 -7
  7. pip/_internal/cli/cmdoptions.py +14 -9
  8. pip/_internal/cli/command_context.py +4 -3
  9. pip/_internal/cli/index_command.py +11 -9
  10. pip/_internal/cli/main.py +3 -2
  11. pip/_internal/cli/main_parser.py +4 -3
  12. pip/_internal/cli/parser.py +26 -22
  13. pip/_internal/cli/progress_bars.py +19 -12
  14. pip/_internal/cli/req_command.py +16 -12
  15. pip/_internal/cli/spinners.py +81 -5
  16. pip/_internal/commands/__init__.py +5 -3
  17. pip/_internal/commands/cache.py +18 -15
  18. pip/_internal/commands/check.py +1 -2
  19. pip/_internal/commands/completion.py +1 -2
  20. pip/_internal/commands/configuration.py +26 -18
  21. pip/_internal/commands/debug.py +8 -6
  22. pip/_internal/commands/download.py +2 -3
  23. pip/_internal/commands/freeze.py +2 -3
  24. pip/_internal/commands/hash.py +1 -2
  25. pip/_internal/commands/help.py +1 -2
  26. pip/_internal/commands/index.py +15 -9
  27. pip/_internal/commands/inspect.py +4 -4
  28. pip/_internal/commands/install.py +44 -39
  29. pip/_internal/commands/list.py +35 -26
  30. pip/_internal/commands/lock.py +1 -2
  31. pip/_internal/commands/search.py +14 -12
  32. pip/_internal/commands/show.py +14 -11
  33. pip/_internal/commands/uninstall.py +1 -2
  34. pip/_internal/commands/wheel.py +2 -3
  35. pip/_internal/configuration.py +39 -25
  36. pip/_internal/distributions/base.py +6 -4
  37. pip/_internal/distributions/installed.py +8 -4
  38. pip/_internal/distributions/sdist.py +20 -13
  39. pip/_internal/distributions/wheel.py +6 -4
  40. pip/_internal/exceptions.py +58 -39
  41. pip/_internal/index/collector.py +24 -29
  42. pip/_internal/index/package_finder.py +70 -61
  43. pip/_internal/index/sources.py +17 -14
  44. pip/_internal/locations/__init__.py +18 -16
  45. pip/_internal/locations/_distutils.py +12 -11
  46. pip/_internal/locations/_sysconfig.py +5 -4
  47. pip/_internal/locations/base.py +4 -3
  48. pip/_internal/main.py +2 -2
  49. pip/_internal/metadata/__init__.py +8 -6
  50. pip/_internal/metadata/_json.py +5 -4
  51. pip/_internal/metadata/base.py +22 -27
  52. pip/_internal/metadata/importlib/_compat.py +6 -4
  53. pip/_internal/metadata/importlib/_dists.py +12 -17
  54. pip/_internal/metadata/importlib/_envs.py +9 -6
  55. pip/_internal/metadata/pkg_resources.py +11 -14
  56. pip/_internal/models/direct_url.py +24 -21
  57. pip/_internal/models/format_control.py +5 -5
  58. pip/_internal/models/installation_report.py +4 -3
  59. pip/_internal/models/link.py +39 -34
  60. pip/_internal/models/pylock.py +27 -22
  61. pip/_internal/models/search_scope.py +6 -7
  62. pip/_internal/models/selection_prefs.py +3 -3
  63. pip/_internal/models/target_python.py +10 -9
  64. pip/_internal/models/wheel.py +7 -5
  65. pip/_internal/network/auth.py +20 -22
  66. pip/_internal/network/cache.py +22 -6
  67. pip/_internal/network/download.py +169 -141
  68. pip/_internal/network/lazy_wheel.py +10 -7
  69. pip/_internal/network/session.py +32 -27
  70. pip/_internal/network/utils.py +2 -2
  71. pip/_internal/network/xmlrpc.py +2 -2
  72. pip/_internal/operations/build/build_tracker.py +10 -8
  73. pip/_internal/operations/build/wheel.py +3 -2
  74. pip/_internal/operations/build/wheel_editable.py +3 -2
  75. pip/_internal/operations/build/wheel_legacy.py +9 -8
  76. pip/_internal/operations/check.py +21 -26
  77. pip/_internal/operations/freeze.py +12 -9
  78. pip/_internal/operations/install/editable_legacy.py +5 -3
  79. pip/_internal/operations/install/wheel.py +49 -41
  80. pip/_internal/operations/prepare.py +35 -30
  81. pip/_internal/pyproject.py +7 -10
  82. pip/_internal/req/__init__.py +12 -10
  83. pip/_internal/req/constructors.py +33 -31
  84. pip/_internal/req/req_dependency_group.py +7 -11
  85. pip/_internal/req/req_file.py +32 -35
  86. pip/_internal/req/req_install.py +37 -34
  87. pip/_internal/req/req_set.py +4 -5
  88. pip/_internal/req/req_uninstall.py +20 -17
  89. pip/_internal/resolution/base.py +3 -3
  90. pip/_internal/resolution/legacy/resolver.py +21 -20
  91. pip/_internal/resolution/resolvelib/base.py +16 -13
  92. pip/_internal/resolution/resolvelib/candidates.py +29 -26
  93. pip/_internal/resolution/resolvelib/factory.py +41 -50
  94. pip/_internal/resolution/resolvelib/found_candidates.py +11 -9
  95. pip/_internal/resolution/resolvelib/provider.py +15 -20
  96. pip/_internal/resolution/resolvelib/reporter.py +5 -3
  97. pip/_internal/resolution/resolvelib/requirements.py +8 -6
  98. pip/_internal/resolution/resolvelib/resolver.py +39 -23
  99. pip/_internal/self_outdated_check.py +8 -6
  100. pip/_internal/utils/appdirs.py +1 -2
  101. pip/_internal/utils/compat.py +7 -1
  102. pip/_internal/utils/compatibility_tags.py +17 -16
  103. pip/_internal/utils/deprecation.py +11 -9
  104. pip/_internal/utils/direct_url_helpers.py +2 -2
  105. pip/_internal/utils/egg_link.py +6 -5
  106. pip/_internal/utils/entrypoints.py +3 -2
  107. pip/_internal/utils/filesystem.py +8 -5
  108. pip/_internal/utils/filetypes.py +4 -6
  109. pip/_internal/utils/glibc.py +6 -5
  110. pip/_internal/utils/hashes.py +9 -6
  111. pip/_internal/utils/logging.py +8 -5
  112. pip/_internal/utils/misc.py +37 -45
  113. pip/_internal/utils/packaging.py +3 -2
  114. pip/_internal/utils/retry.py +7 -4
  115. pip/_internal/utils/setuptools_build.py +12 -10
  116. pip/_internal/utils/subprocess.py +20 -17
  117. pip/_internal/utils/temp_dir.py +10 -12
  118. pip/_internal/utils/unpacking.py +6 -4
  119. pip/_internal/utils/urls.py +1 -1
  120. pip/_internal/utils/virtualenv.py +3 -2
  121. pip/_internal/utils/wheel.py +3 -4
  122. pip/_internal/vcs/bazaar.py +26 -8
  123. pip/_internal/vcs/git.py +59 -24
  124. pip/_internal/vcs/mercurial.py +34 -11
  125. pip/_internal/vcs/subversion.py +27 -16
  126. pip/_internal/vcs/versioncontrol.py +56 -51
  127. pip/_internal/wheel_builder.py +14 -12
  128. pip/_vendor/cachecontrol/__init__.py +1 -1
  129. pip/_vendor/certifi/__init__.py +1 -1
  130. pip/_vendor/certifi/cacert.pem +102 -221
  131. pip/_vendor/certifi/core.py +1 -32
  132. pip/_vendor/distlib/__init__.py +2 -2
  133. pip/_vendor/distlib/scripts.py +1 -1
  134. pip/_vendor/msgpack/__init__.py +2 -2
  135. pip/_vendor/pkg_resources/__init__.py +1 -1
  136. pip/_vendor/platformdirs/version.py +2 -2
  137. pip/_vendor/pygments/__init__.py +1 -1
  138. pip/_vendor/requests/__version__.py +2 -2
  139. pip/_vendor/requests/compat.py +12 -0
  140. pip/_vendor/requests/models.py +3 -1
  141. pip/_vendor/requests/utils.py +6 -16
  142. pip/_vendor/resolvelib/__init__.py +3 -3
  143. pip/_vendor/resolvelib/reporters.py +1 -1
  144. pip/_vendor/resolvelib/resolvers/__init__.py +4 -4
  145. pip/_vendor/resolvelib/resolvers/resolution.py +91 -10
  146. pip/_vendor/rich/__main__.py +12 -40
  147. pip/_vendor/rich/_inspect.py +1 -1
  148. pip/_vendor/rich/_ratio.py +1 -7
  149. pip/_vendor/rich/align.py +1 -7
  150. pip/_vendor/rich/box.py +1 -7
  151. pip/_vendor/rich/console.py +25 -20
  152. pip/_vendor/rich/control.py +1 -7
  153. pip/_vendor/rich/diagnose.py +1 -0
  154. pip/_vendor/rich/emoji.py +1 -6
  155. pip/_vendor/rich/live.py +32 -7
  156. pip/_vendor/rich/live_render.py +1 -7
  157. pip/_vendor/rich/logging.py +1 -1
  158. pip/_vendor/rich/panel.py +3 -4
  159. pip/_vendor/rich/progress.py +15 -15
  160. pip/_vendor/rich/spinner.py +7 -13
  161. pip/_vendor/rich/syntax.py +24 -5
  162. pip/_vendor/rich/traceback.py +32 -17
  163. pip/_vendor/truststore/_api.py +1 -1
  164. pip/_vendor/vendor.txt +9 -10
  165. {pip-25.1.1.dist-info → pip-25.2.dist-info}/METADATA +26 -4
  166. {pip-25.1.1.dist-info → pip-25.2.dist-info}/RECORD +193 -180
  167. {pip-25.1.1.dist-info → pip-25.2.dist-info}/WHEEL +1 -1
  168. {pip-25.1.1.dist-info → pip-25.2.dist-info}/licenses/AUTHORS.txt +12 -0
  169. pip-25.2.dist-info/licenses/src/pip/_vendor/cachecontrol/LICENSE.txt +13 -0
  170. pip-25.2.dist-info/licenses/src/pip/_vendor/certifi/LICENSE +20 -0
  171. pip-25.2.dist-info/licenses/src/pip/_vendor/dependency_groups/LICENSE.txt +9 -0
  172. pip-25.2.dist-info/licenses/src/pip/_vendor/distlib/LICENSE.txt +284 -0
  173. pip-25.2.dist-info/licenses/src/pip/_vendor/distro/LICENSE +202 -0
  174. pip-25.2.dist-info/licenses/src/pip/_vendor/idna/LICENSE.md +31 -0
  175. pip-25.2.dist-info/licenses/src/pip/_vendor/msgpack/COPYING +14 -0
  176. pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE +3 -0
  177. pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.APACHE +177 -0
  178. pip-25.2.dist-info/licenses/src/pip/_vendor/packaging/LICENSE.BSD +23 -0
  179. pip-25.2.dist-info/licenses/src/pip/_vendor/pkg_resources/LICENSE +17 -0
  180. pip-25.2.dist-info/licenses/src/pip/_vendor/platformdirs/LICENSE +21 -0
  181. pip-25.2.dist-info/licenses/src/pip/_vendor/pygments/LICENSE +25 -0
  182. pip-25.2.dist-info/licenses/src/pip/_vendor/pyproject_hooks/LICENSE +21 -0
  183. pip-25.2.dist-info/licenses/src/pip/_vendor/requests/LICENSE +175 -0
  184. pip-25.2.dist-info/licenses/src/pip/_vendor/resolvelib/LICENSE +13 -0
  185. pip-25.2.dist-info/licenses/src/pip/_vendor/rich/LICENSE +19 -0
  186. pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE +21 -0
  187. pip-25.2.dist-info/licenses/src/pip/_vendor/tomli/LICENSE-HEADER +3 -0
  188. pip-25.2.dist-info/licenses/src/pip/_vendor/tomli_w/LICENSE +21 -0
  189. pip-25.2.dist-info/licenses/src/pip/_vendor/truststore/LICENSE +21 -0
  190. pip-25.2.dist-info/licenses/src/pip/_vendor/urllib3/LICENSE.txt +21 -0
  191. pip/_vendor/distlib/database.py +0 -1329
  192. pip/_vendor/distlib/index.py +0 -508
  193. pip/_vendor/distlib/locators.py +0 -1295
  194. pip/_vendor/distlib/manifest.py +0 -384
  195. pip/_vendor/distlib/markers.py +0 -162
  196. pip/_vendor/distlib/metadata.py +0 -1031
  197. pip/_vendor/distlib/version.py +0 -750
  198. pip/_vendor/distlib/wheel.py +0 -1100
  199. pip/_vendor/typing_extensions.py +0 -4584
  200. {pip-25.1.1.dist-info → pip-25.2.dist-info}/entry_points.txt +0 -0
  201. {pip-25.1.1.dist-info → pip-25.2.dist-info}/licenses/LICENSE.txt +0 -0
  202. {pip-25.1.1.dist-info → pip-25.2.dist-info}/top_level.txt +0 -0
@@ -1,384 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2012-2023 Python Software Foundation.
4
- # See LICENSE.txt and CONTRIBUTORS.txt.
5
- #
6
- """
7
- Class representing the list of files in a distribution.
8
-
9
- Equivalent to distutils.filelist, but fixes some problems.
10
- """
11
- import fnmatch
12
- import logging
13
- import os
14
- import re
15
- import sys
16
-
17
- from . import DistlibException
18
- from .compat import fsdecode
19
- from .util import convert_path
20
-
21
-
22
- __all__ = ['Manifest']
23
-
24
- logger = logging.getLogger(__name__)
25
-
26
- # a \ followed by some spaces + EOL
27
- _COLLAPSE_PATTERN = re.compile('\\\\w*\n', re.M)
28
- _COMMENTED_LINE = re.compile('#.*?(?=\n)|\n(?=$)', re.M | re.S)
29
-
30
- #
31
- # Due to the different results returned by fnmatch.translate, we need
32
- # to do slightly different processing for Python 2.7 and 3.2 ... this needed
33
- # to be brought in for Python 3.6 onwards.
34
- #
35
- _PYTHON_VERSION = sys.version_info[:2]
36
-
37
-
38
- class Manifest(object):
39
- """
40
- A list of files built by exploring the filesystem and filtered by applying various
41
- patterns to what we find there.
42
- """
43
-
44
- def __init__(self, base=None):
45
- """
46
- Initialise an instance.
47
-
48
- :param base: The base directory to explore under.
49
- """
50
- self.base = os.path.abspath(os.path.normpath(base or os.getcwd()))
51
- self.prefix = self.base + os.sep
52
- self.allfiles = None
53
- self.files = set()
54
-
55
- #
56
- # Public API
57
- #
58
-
59
- def findall(self):
60
- """Find all files under the base and set ``allfiles`` to the absolute
61
- pathnames of files found.
62
- """
63
- from stat import S_ISREG, S_ISDIR, S_ISLNK
64
-
65
- self.allfiles = allfiles = []
66
- root = self.base
67
- stack = [root]
68
- pop = stack.pop
69
- push = stack.append
70
-
71
- while stack:
72
- root = pop()
73
- names = os.listdir(root)
74
-
75
- for name in names:
76
- fullname = os.path.join(root, name)
77
-
78
- # Avoid excess stat calls -- just one will do, thank you!
79
- stat = os.stat(fullname)
80
- mode = stat.st_mode
81
- if S_ISREG(mode):
82
- allfiles.append(fsdecode(fullname))
83
- elif S_ISDIR(mode) and not S_ISLNK(mode):
84
- push(fullname)
85
-
86
- def add(self, item):
87
- """
88
- Add a file to the manifest.
89
-
90
- :param item: The pathname to add. This can be relative to the base.
91
- """
92
- if not item.startswith(self.prefix):
93
- item = os.path.join(self.base, item)
94
- self.files.add(os.path.normpath(item))
95
-
96
- def add_many(self, items):
97
- """
98
- Add a list of files to the manifest.
99
-
100
- :param items: The pathnames to add. These can be relative to the base.
101
- """
102
- for item in items:
103
- self.add(item)
104
-
105
- def sorted(self, wantdirs=False):
106
- """
107
- Return sorted files in directory order
108
- """
109
-
110
- def add_dir(dirs, d):
111
- dirs.add(d)
112
- logger.debug('add_dir added %s', d)
113
- if d != self.base:
114
- parent, _ = os.path.split(d)
115
- assert parent not in ('', '/')
116
- add_dir(dirs, parent)
117
-
118
- result = set(self.files) # make a copy!
119
- if wantdirs:
120
- dirs = set()
121
- for f in result:
122
- add_dir(dirs, os.path.dirname(f))
123
- result |= dirs
124
- return [os.path.join(*path_tuple) for path_tuple in
125
- sorted(os.path.split(path) for path in result)]
126
-
127
- def clear(self):
128
- """Clear all collected files."""
129
- self.files = set()
130
- self.allfiles = []
131
-
132
- def process_directive(self, directive):
133
- """
134
- Process a directive which either adds some files from ``allfiles`` to
135
- ``files``, or removes some files from ``files``.
136
-
137
- :param directive: The directive to process. This should be in a format
138
- compatible with distutils ``MANIFEST.in`` files:
139
-
140
- http://docs.python.org/distutils/sourcedist.html#commands
141
- """
142
- # Parse the line: split it up, make sure the right number of words
143
- # is there, and return the relevant words. 'action' is always
144
- # defined: it's the first word of the line. Which of the other
145
- # three are defined depends on the action; it'll be either
146
- # patterns, (dir and patterns), or (dirpattern).
147
- action, patterns, thedir, dirpattern = self._parse_directive(directive)
148
-
149
- # OK, now we know that the action is valid and we have the
150
- # right number of words on the line for that action -- so we
151
- # can proceed with minimal error-checking.
152
- if action == 'include':
153
- for pattern in patterns:
154
- if not self._include_pattern(pattern, anchor=True):
155
- logger.warning('no files found matching %r', pattern)
156
-
157
- elif action == 'exclude':
158
- for pattern in patterns:
159
- self._exclude_pattern(pattern, anchor=True)
160
-
161
- elif action == 'global-include':
162
- for pattern in patterns:
163
- if not self._include_pattern(pattern, anchor=False):
164
- logger.warning('no files found matching %r '
165
- 'anywhere in distribution', pattern)
166
-
167
- elif action == 'global-exclude':
168
- for pattern in patterns:
169
- self._exclude_pattern(pattern, anchor=False)
170
-
171
- elif action == 'recursive-include':
172
- for pattern in patterns:
173
- if not self._include_pattern(pattern, prefix=thedir):
174
- logger.warning('no files found matching %r '
175
- 'under directory %r', pattern, thedir)
176
-
177
- elif action == 'recursive-exclude':
178
- for pattern in patterns:
179
- self._exclude_pattern(pattern, prefix=thedir)
180
-
181
- elif action == 'graft':
182
- if not self._include_pattern(None, prefix=dirpattern):
183
- logger.warning('no directories found matching %r',
184
- dirpattern)
185
-
186
- elif action == 'prune':
187
- if not self._exclude_pattern(None, prefix=dirpattern):
188
- logger.warning('no previously-included directories found '
189
- 'matching %r', dirpattern)
190
- else: # pragma: no cover
191
- # This should never happen, as it should be caught in
192
- # _parse_template_line
193
- raise DistlibException(
194
- 'invalid action %r' % action)
195
-
196
- #
197
- # Private API
198
- #
199
-
200
- def _parse_directive(self, directive):
201
- """
202
- Validate a directive.
203
- :param directive: The directive to validate.
204
- :return: A tuple of action, patterns, thedir, dir_patterns
205
- """
206
- words = directive.split()
207
- if len(words) == 1 and words[0] not in ('include', 'exclude',
208
- 'global-include',
209
- 'global-exclude',
210
- 'recursive-include',
211
- 'recursive-exclude',
212
- 'graft', 'prune'):
213
- # no action given, let's use the default 'include'
214
- words.insert(0, 'include')
215
-
216
- action = words[0]
217
- patterns = thedir = dir_pattern = None
218
-
219
- if action in ('include', 'exclude',
220
- 'global-include', 'global-exclude'):
221
- if len(words) < 2:
222
- raise DistlibException(
223
- '%r expects <pattern1> <pattern2> ...' % action)
224
-
225
- patterns = [convert_path(word) for word in words[1:]]
226
-
227
- elif action in ('recursive-include', 'recursive-exclude'):
228
- if len(words) < 3:
229
- raise DistlibException(
230
- '%r expects <dir> <pattern1> <pattern2> ...' % action)
231
-
232
- thedir = convert_path(words[1])
233
- patterns = [convert_path(word) for word in words[2:]]
234
-
235
- elif action in ('graft', 'prune'):
236
- if len(words) != 2:
237
- raise DistlibException(
238
- '%r expects a single <dir_pattern>' % action)
239
-
240
- dir_pattern = convert_path(words[1])
241
-
242
- else:
243
- raise DistlibException('unknown action %r' % action)
244
-
245
- return action, patterns, thedir, dir_pattern
246
-
247
- def _include_pattern(self, pattern, anchor=True, prefix=None,
248
- is_regex=False):
249
- """Select strings (presumably filenames) from 'self.files' that
250
- match 'pattern', a Unix-style wildcard (glob) pattern.
251
-
252
- Patterns are not quite the same as implemented by the 'fnmatch'
253
- module: '*' and '?' match non-special characters, where "special"
254
- is platform-dependent: slash on Unix; colon, slash, and backslash on
255
- DOS/Windows; and colon on Mac OS.
256
-
257
- If 'anchor' is true (the default), then the pattern match is more
258
- stringent: "*.py" will match "foo.py" but not "foo/bar.py". If
259
- 'anchor' is false, both of these will match.
260
-
261
- If 'prefix' is supplied, then only filenames starting with 'prefix'
262
- (itself a pattern) and ending with 'pattern', with anything in between
263
- them, will match. 'anchor' is ignored in this case.
264
-
265
- If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and
266
- 'pattern' is assumed to be either a string containing a regex or a
267
- regex object -- no translation is done, the regex is just compiled
268
- and used as-is.
269
-
270
- Selected strings will be added to self.files.
271
-
272
- Return True if files are found.
273
- """
274
- # XXX docstring lying about what the special chars are?
275
- found = False
276
- pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex)
277
-
278
- # delayed loading of allfiles list
279
- if self.allfiles is None:
280
- self.findall()
281
-
282
- for name in self.allfiles:
283
- if pattern_re.search(name):
284
- self.files.add(name)
285
- found = True
286
- return found
287
-
288
- def _exclude_pattern(self, pattern, anchor=True, prefix=None,
289
- is_regex=False):
290
- """Remove strings (presumably filenames) from 'files' that match
291
- 'pattern'.
292
-
293
- Other parameters are the same as for 'include_pattern()', above.
294
- The list 'self.files' is modified in place. Return True if files are
295
- found.
296
-
297
- This API is public to allow e.g. exclusion of SCM subdirs, e.g. when
298
- packaging source distributions
299
- """
300
- found = False
301
- pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex)
302
- for f in list(self.files):
303
- if pattern_re.search(f):
304
- self.files.remove(f)
305
- found = True
306
- return found
307
-
308
- def _translate_pattern(self, pattern, anchor=True, prefix=None,
309
- is_regex=False):
310
- """Translate a shell-like wildcard pattern to a compiled regular
311
- expression.
312
-
313
- Return the compiled regex. If 'is_regex' true,
314
- then 'pattern' is directly compiled to a regex (if it's a string)
315
- or just returned as-is (assumes it's a regex object).
316
- """
317
- if is_regex:
318
- if isinstance(pattern, str):
319
- return re.compile(pattern)
320
- else:
321
- return pattern
322
-
323
- if _PYTHON_VERSION > (3, 2):
324
- # ditch start and end characters
325
- start, _, end = self._glob_to_re('_').partition('_')
326
-
327
- if pattern:
328
- pattern_re = self._glob_to_re(pattern)
329
- if _PYTHON_VERSION > (3, 2):
330
- assert pattern_re.startswith(start) and pattern_re.endswith(end)
331
- else:
332
- pattern_re = ''
333
-
334
- base = re.escape(os.path.join(self.base, ''))
335
- if prefix is not None:
336
- # ditch end of pattern character
337
- if _PYTHON_VERSION <= (3, 2):
338
- empty_pattern = self._glob_to_re('')
339
- prefix_re = self._glob_to_re(prefix)[:-len(empty_pattern)]
340
- else:
341
- prefix_re = self._glob_to_re(prefix)
342
- assert prefix_re.startswith(start) and prefix_re.endswith(end)
343
- prefix_re = prefix_re[len(start): len(prefix_re) - len(end)]
344
- sep = os.sep
345
- if os.sep == '\\':
346
- sep = r'\\'
347
- if _PYTHON_VERSION <= (3, 2):
348
- pattern_re = '^' + base + sep.join((prefix_re,
349
- '.*' + pattern_re))
350
- else:
351
- pattern_re = pattern_re[len(start): len(pattern_re) - len(end)]
352
- pattern_re = r'%s%s%s%s.*%s%s' % (start, base, prefix_re, sep,
353
- pattern_re, end)
354
- else: # no prefix -- respect anchor flag
355
- if anchor:
356
- if _PYTHON_VERSION <= (3, 2):
357
- pattern_re = '^' + base + pattern_re
358
- else:
359
- pattern_re = r'%s%s%s' % (start, base, pattern_re[len(start):])
360
-
361
- return re.compile(pattern_re)
362
-
363
- def _glob_to_re(self, pattern):
364
- """Translate a shell-like glob pattern to a regular expression.
365
-
366
- Return a string containing the regex. Differs from
367
- 'fnmatch.translate()' in that '*' does not match "special characters"
368
- (which are platform-specific).
369
- """
370
- pattern_re = fnmatch.translate(pattern)
371
-
372
- # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which
373
- # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix,
374
- # and by extension they shouldn't match such "special characters" under
375
- # any OS. So change all non-escaped dots in the RE to match any
376
- # character except the special characters (currently: just os.sep).
377
- sep = os.sep
378
- if os.sep == '\\':
379
- # we're using a regex to manipulate a regex, so we need
380
- # to escape the backslash twice
381
- sep = r'\\\\'
382
- escaped = r'\1[^%s]' % sep
383
- pattern_re = re.sub(r'((?<!\\)(\\\\)*)\.', escaped, pattern_re)
384
- return pattern_re
@@ -1,162 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- #
3
- # Copyright (C) 2012-2023 Vinay Sajip.
4
- # Licensed to the Python Software Foundation under a contributor agreement.
5
- # See LICENSE.txt and CONTRIBUTORS.txt.
6
- #
7
- """
8
- Parser for the environment markers micro-language defined in PEP 508.
9
- """
10
-
11
- # Note: In PEP 345, the micro-language was Python compatible, so the ast
12
- # module could be used to parse it. However, PEP 508 introduced operators such
13
- # as ~= and === which aren't in Python, necessitating a different approach.
14
-
15
- import os
16
- import re
17
- import sys
18
- import platform
19
-
20
- from .compat import string_types
21
- from .util import in_venv, parse_marker
22
- from .version import LegacyVersion as LV
23
-
24
- __all__ = ['interpret']
25
-
26
- _VERSION_PATTERN = re.compile(r'((\d+(\.\d+)*\w*)|\'(\d+(\.\d+)*\w*)\'|\"(\d+(\.\d+)*\w*)\")')
27
- _VERSION_MARKERS = {'python_version', 'python_full_version'}
28
-
29
-
30
- def _is_version_marker(s):
31
- return isinstance(s, string_types) and s in _VERSION_MARKERS
32
-
33
-
34
- def _is_literal(o):
35
- if not isinstance(o, string_types) or not o:
36
- return False
37
- return o[0] in '\'"'
38
-
39
-
40
- def _get_versions(s):
41
- return {LV(m.groups()[0]) for m in _VERSION_PATTERN.finditer(s)}
42
-
43
-
44
- class Evaluator(object):
45
- """
46
- This class is used to evaluate marker expressions.
47
- """
48
-
49
- operations = {
50
- '==': lambda x, y: x == y,
51
- '===': lambda x, y: x == y,
52
- '~=': lambda x, y: x == y or x > y,
53
- '!=': lambda x, y: x != y,
54
- '<': lambda x, y: x < y,
55
- '<=': lambda x, y: x == y or x < y,
56
- '>': lambda x, y: x > y,
57
- '>=': lambda x, y: x == y or x > y,
58
- 'and': lambda x, y: x and y,
59
- 'or': lambda x, y: x or y,
60
- 'in': lambda x, y: x in y,
61
- 'not in': lambda x, y: x not in y,
62
- }
63
-
64
- def evaluate(self, expr, context):
65
- """
66
- Evaluate a marker expression returned by the :func:`parse_requirement`
67
- function in the specified context.
68
- """
69
- if isinstance(expr, string_types):
70
- if expr[0] in '\'"':
71
- result = expr[1:-1]
72
- else:
73
- if expr not in context:
74
- raise SyntaxError('unknown variable: %s' % expr)
75
- result = context[expr]
76
- else:
77
- assert isinstance(expr, dict)
78
- op = expr['op']
79
- if op not in self.operations:
80
- raise NotImplementedError('op not implemented: %s' % op)
81
- elhs = expr['lhs']
82
- erhs = expr['rhs']
83
- if _is_literal(expr['lhs']) and _is_literal(expr['rhs']):
84
- raise SyntaxError('invalid comparison: %s %s %s' % (elhs, op, erhs))
85
-
86
- lhs = self.evaluate(elhs, context)
87
- rhs = self.evaluate(erhs, context)
88
- if ((_is_version_marker(elhs) or _is_version_marker(erhs)) and
89
- op in ('<', '<=', '>', '>=', '===', '==', '!=', '~=')):
90
- lhs = LV(lhs)
91
- rhs = LV(rhs)
92
- elif _is_version_marker(elhs) and op in ('in', 'not in'):
93
- lhs = LV(lhs)
94
- rhs = _get_versions(rhs)
95
- result = self.operations[op](lhs, rhs)
96
- return result
97
-
98
-
99
- _DIGITS = re.compile(r'\d+\.\d+')
100
-
101
-
102
- def default_context():
103
-
104
- def format_full_version(info):
105
- version = '%s.%s.%s' % (info.major, info.minor, info.micro)
106
- kind = info.releaselevel
107
- if kind != 'final':
108
- version += kind[0] + str(info.serial)
109
- return version
110
-
111
- if hasattr(sys, 'implementation'):
112
- implementation_version = format_full_version(sys.implementation.version)
113
- implementation_name = sys.implementation.name
114
- else:
115
- implementation_version = '0'
116
- implementation_name = ''
117
-
118
- ppv = platform.python_version()
119
- m = _DIGITS.match(ppv)
120
- pv = m.group(0)
121
- result = {
122
- 'implementation_name': implementation_name,
123
- 'implementation_version': implementation_version,
124
- 'os_name': os.name,
125
- 'platform_machine': platform.machine(),
126
- 'platform_python_implementation': platform.python_implementation(),
127
- 'platform_release': platform.release(),
128
- 'platform_system': platform.system(),
129
- 'platform_version': platform.version(),
130
- 'platform_in_venv': str(in_venv()),
131
- 'python_full_version': ppv,
132
- 'python_version': pv,
133
- 'sys_platform': sys.platform,
134
- }
135
- return result
136
-
137
-
138
- DEFAULT_CONTEXT = default_context()
139
- del default_context
140
-
141
- evaluator = Evaluator()
142
-
143
-
144
- def interpret(marker, execution_context=None):
145
- """
146
- Interpret a marker and return a result depending on environment.
147
-
148
- :param marker: The marker to interpret.
149
- :type marker: str
150
- :param execution_context: The context used for name lookup.
151
- :type execution_context: mapping
152
- """
153
- try:
154
- expr, rest = parse_marker(marker)
155
- except Exception as e:
156
- raise SyntaxError('Unable to interpret marker syntax: %s: %s' % (marker, e))
157
- if rest and rest[0] != '#':
158
- raise SyntaxError('unexpected trailing data in marker: %s: %s' % (marker, rest))
159
- context = dict(DEFAULT_CONTEXT)
160
- if execution_context:
161
- context.update(execution_context)
162
- return evaluator.evaluate(expr, context)