BryanW commited on
Commit
1611dcd
·
verified ·
1 Parent(s): 3c9b244

Add files using upload-large-folder tool

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/_core_metadata.cpython-312.pyc +0 -0
  2. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/_entry_points.cpython-312.pyc +0 -0
  3. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/_importlib.cpython-312.pyc +0 -0
  4. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/_reqs.cpython-312.pyc +0 -0
  5. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/build_meta.cpython-312.pyc +0 -0
  6. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/discovery.cpython-312.pyc +0 -0
  7. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/installer.cpython-312.pyc +0 -0
  8. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/logging.cpython-312.pyc +0 -0
  9. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/wheel.cpython-312.pyc +0 -0
  10. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/windows_support.cpython-312.pyc +0 -0
  11. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/_requirestxt.py +131 -0
  12. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/bdist_egg.py +464 -0
  13. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/bdist_rpm.py +39 -0
  14. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/bdist_wheel.py +597 -0
  15. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/build_py.py +401 -0
  16. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/develop.py +196 -0
  17. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/dist_info.py +106 -0
  18. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/editable_wheel.py +918 -0
  19. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/egg_info.py +737 -0
  20. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/install_lib.py +126 -0
  21. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/install_scripts.py +68 -0
  22. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/launcher manifest.xml +15 -0
  23. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/register.py +18 -0
  24. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/rotate.py +64 -0
  25. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/sdist.py +204 -0
  26. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/setopt.py +140 -0
  27. URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/test.py +250 -0
  28. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/__autotune_main__.cpython-312.pyc +0 -0
  29. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/__init__.cpython-312.pyc +0 -0
  30. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/aoti_eager.cpython-312.pyc +0 -0
  31. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/autotune_process.cpython-312.pyc +0 -0
  32. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/await_utils.cpython-312.pyc +0 -0
  33. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/bounds.cpython-312.pyc +0 -0
  34. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/cache.cpython-312.pyc +0 -0
  35. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/comm_analysis.cpython-312.pyc +0 -0
  36. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/comm_lowering.cpython-312.pyc +0 -0
  37. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/comms.cpython-312.pyc +0 -0
  38. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/comms_debug.cpython-312.pyc +0 -0
  39. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/compile_fx_subproc.cpython-312.pyc +0 -0
  40. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/config_comms.cpython-312.pyc +0 -0
  41. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/constant_folding.cpython-312.pyc +0 -0
  42. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/cpp_builder.cpython-312.pyc +0 -0
  43. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/cpu_vec_isa.cpython-312.pyc +0 -0
  44. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/custom_graph_pass.cpython-312.pyc +0 -0
  45. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/debug.cpython-312.pyc +0 -0
  46. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/decomposition.cpython-312.pyc +0 -0
  47. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/dependencies.cpython-312.pyc +0 -0
  48. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/distributed_autotune.cpython-312.pyc +0 -0
  49. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/exc.cpython-312.pyc +0 -0
  50. URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/extern_node_serializer.cpython-312.pyc +0 -0
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/_core_metadata.cpython-312.pyc ADDED
Binary file (13.4 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/_entry_points.cpython-312.pyc ADDED
Binary file (4.73 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/_importlib.cpython-312.pyc ADDED
Binary file (1.81 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/_reqs.cpython-312.pyc ADDED
Binary file (1.87 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/build_meta.cpython-312.pyc ADDED
Binary file (23.7 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/discovery.cpython-312.pyc ADDED
Binary file (28.4 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/installer.cpython-312.pyc ADDED
Binary file (6.48 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/logging.cpython-312.pyc ADDED
Binary file (2.07 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/wheel.cpython-312.pyc ADDED
Binary file (13.5 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/__pycache__/windows_support.cpython-312.pyc ADDED
Binary file (1.47 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/_requirestxt.py ADDED
@@ -0,0 +1,131 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Helper code used to generate ``requires.txt`` files in the egg-info directory.
2
+
3
+ The ``requires.txt`` file has an specific format:
4
+ - Environment markers need to be part of the section headers and
5
+ should not be part of the requirement spec itself.
6
+
7
+ See https://setuptools.pypa.io/en/latest/deprecated/python_eggs.html#requires-txt
8
+ """
9
+
10
+ from __future__ import annotations
11
+
12
+ import io
13
+ from collections import defaultdict
14
+ from itertools import filterfalse
15
+ from typing import Dict, Mapping, TypeVar
16
+
17
+ from .. import _reqs
18
+ from ..extern.jaraco.text import yield_lines
19
+ from ..extern.packaging.requirements import Requirement
20
+
21
+
22
+ # dict can work as an ordered set
23
+ _T = TypeVar("_T")
24
+ _Ordered = Dict[_T, None]
25
+ _ordered = dict
26
+ _StrOrIter = _reqs._StrOrIter
27
+
28
+
29
+ def _prepare(
30
+ install_requires: _StrOrIter, extras_require: Mapping[str, _StrOrIter]
31
+ ) -> tuple[list[str], dict[str, list[str]]]:
32
+ """Given values for ``install_requires`` and ``extras_require``
33
+ create modified versions in a way that can be written in ``requires.txt``
34
+ """
35
+ extras = _convert_extras_requirements(extras_require)
36
+ return _move_install_requirements_markers(install_requires, extras)
37
+
38
+
39
+ def _convert_extras_requirements(
40
+ extras_require: Mapping[str, _StrOrIter],
41
+ ) -> Mapping[str, _Ordered[Requirement]]:
42
+ """
43
+ Convert requirements in `extras_require` of the form
44
+ `"extra": ["barbazquux; {marker}"]` to
45
+ `"extra:{marker}": ["barbazquux"]`.
46
+ """
47
+ output: Mapping[str, _Ordered[Requirement]] = defaultdict(dict)
48
+ for section, v in extras_require.items():
49
+ # Do not strip empty sections.
50
+ output[section]
51
+ for r in _reqs.parse(v):
52
+ output[section + _suffix_for(r)].setdefault(r)
53
+
54
+ return output
55
+
56
+
57
+ def _move_install_requirements_markers(
58
+ install_requires: _StrOrIter, extras_require: Mapping[str, _Ordered[Requirement]]
59
+ ) -> tuple[list[str], dict[str, list[str]]]:
60
+ """
61
+ The ``requires.txt`` file has an specific format:
62
+ - Environment markers need to be part of the section headers and
63
+ should not be part of the requirement spec itself.
64
+
65
+ Move requirements in ``install_requires`` that are using environment
66
+ markers ``extras_require``.
67
+ """
68
+
69
+ # divide the install_requires into two sets, simple ones still
70
+ # handled by install_requires and more complex ones handled by extras_require.
71
+
72
+ inst_reqs = list(_reqs.parse(install_requires))
73
+ simple_reqs = filter(_no_marker, inst_reqs)
74
+ complex_reqs = filterfalse(_no_marker, inst_reqs)
75
+ simple_install_requires = list(map(str, simple_reqs))
76
+
77
+ for r in complex_reqs:
78
+ extras_require[':' + str(r.marker)].setdefault(r)
79
+
80
+ expanded_extras = dict(
81
+ # list(dict.fromkeys(...)) ensures a list of unique strings
82
+ (k, list(dict.fromkeys(str(r) for r in map(_clean_req, v))))
83
+ for k, v in extras_require.items()
84
+ )
85
+
86
+ return simple_install_requires, expanded_extras
87
+
88
+
89
+ def _suffix_for(req):
90
+ """Return the 'extras_require' suffix for a given requirement."""
91
+ return ':' + str(req.marker) if req.marker else ''
92
+
93
+
94
+ def _clean_req(req):
95
+ """Given a Requirement, remove environment markers and return it"""
96
+ r = Requirement(str(req)) # create a copy before modifying
97
+ r.marker = None
98
+ return r
99
+
100
+
101
+ def _no_marker(req):
102
+ return not req.marker
103
+
104
+
105
+ def _write_requirements(stream, reqs):
106
+ lines = yield_lines(reqs or ())
107
+
108
+ def append_cr(line):
109
+ return line + '\n'
110
+
111
+ lines = map(append_cr, lines)
112
+ stream.writelines(lines)
113
+
114
+
115
+ def write_requirements(cmd, basename, filename):
116
+ dist = cmd.distribution
117
+ data = io.StringIO()
118
+ install_requires, extras_require = _prepare(
119
+ dist.install_requires or (), dist.extras_require or {}
120
+ )
121
+ _write_requirements(data, install_requires)
122
+ for extra in sorted(extras_require):
123
+ data.write('\n[{extra}]\n'.format(**vars()))
124
+ _write_requirements(data, extras_require[extra])
125
+ cmd.write_or_delete_file("requirements", filename, data.getvalue())
126
+
127
+
128
+ def write_setup_requirements(cmd, basename, filename):
129
+ data = io.StringIO()
130
+ _write_requirements(data, cmd.distribution.setup_requires)
131
+ cmd.write_or_delete_file("setup-requirements", filename, data.getvalue())
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/bdist_egg.py ADDED
@@ -0,0 +1,464 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """setuptools.command.bdist_egg
2
+
3
+ Build .egg distributions"""
4
+
5
+ from distutils.dir_util import remove_tree, mkpath
6
+ from distutils import log
7
+ from types import CodeType
8
+ import sys
9
+ import os
10
+ import re
11
+ import textwrap
12
+ import marshal
13
+
14
+ from setuptools.extension import Library
15
+ from setuptools import Command
16
+ from .._path import ensure_directory
17
+
18
+ from sysconfig import get_path, get_python_version
19
+
20
+
21
+ def _get_purelib():
22
+ return get_path("purelib")
23
+
24
+
25
+ def strip_module(filename):
26
+ if '.' in filename:
27
+ filename = os.path.splitext(filename)[0]
28
+ if filename.endswith('module'):
29
+ filename = filename[:-6]
30
+ return filename
31
+
32
+
33
+ def sorted_walk(dir):
34
+ """Do os.walk in a reproducible way,
35
+ independent of indeterministic filesystem readdir order
36
+ """
37
+ for base, dirs, files in os.walk(dir):
38
+ dirs.sort()
39
+ files.sort()
40
+ yield base, dirs, files
41
+
42
+
43
+ def write_stub(resource, pyfile):
44
+ _stub_template = textwrap.dedent(
45
+ """
46
+ def __bootstrap__():
47
+ global __bootstrap__, __loader__, __file__
48
+ import sys, pkg_resources, importlib.util
49
+ __file__ = pkg_resources.resource_filename(__name__, %r)
50
+ __loader__ = None; del __bootstrap__, __loader__
51
+ spec = importlib.util.spec_from_file_location(__name__,__file__)
52
+ mod = importlib.util.module_from_spec(spec)
53
+ spec.loader.exec_module(mod)
54
+ __bootstrap__()
55
+ """
56
+ ).lstrip()
57
+ with open(pyfile, 'w', encoding="utf-8") as f:
58
+ f.write(_stub_template % resource)
59
+
60
+
61
+ class bdist_egg(Command):
62
+ description = "create an \"egg\" distribution"
63
+
64
+ user_options = [
65
+ ('bdist-dir=', 'b', "temporary directory for creating the distribution"),
66
+ (
67
+ 'plat-name=',
68
+ 'p',
69
+ "platform name to embed in generated filenames "
70
+ "(by default uses `pkg_resources.get_build_platform()`)",
71
+ ),
72
+ ('exclude-source-files', None, "remove all .py files from the generated egg"),
73
+ (
74
+ 'keep-temp',
75
+ 'k',
76
+ "keep the pseudo-installation tree around after "
77
+ "creating the distribution archive",
78
+ ),
79
+ ('dist-dir=', 'd', "directory to put final built distributions in"),
80
+ ('skip-build', None, "skip rebuilding everything (for testing/debugging)"),
81
+ ]
82
+
83
+ boolean_options = ['keep-temp', 'skip-build', 'exclude-source-files']
84
+
85
+ def initialize_options(self):
86
+ self.bdist_dir = None
87
+ self.plat_name = None
88
+ self.keep_temp = False
89
+ self.dist_dir = None
90
+ self.skip_build = False
91
+ self.egg_output = None
92
+ self.exclude_source_files = None
93
+
94
+ def finalize_options(self):
95
+ ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info")
96
+ self.egg_info = ei_cmd.egg_info
97
+
98
+ if self.bdist_dir is None:
99
+ bdist_base = self.get_finalized_command('bdist').bdist_base
100
+ self.bdist_dir = os.path.join(bdist_base, 'egg')
101
+
102
+ if self.plat_name is None:
103
+ from pkg_resources import get_build_platform
104
+
105
+ self.plat_name = get_build_platform()
106
+
107
+ self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
108
+
109
+ if self.egg_output is None:
110
+ # Compute filename of the output egg
111
+ basename = ei_cmd._get_egg_basename(
112
+ py_version=get_python_version(),
113
+ platform=self.distribution.has_ext_modules() and self.plat_name,
114
+ )
115
+
116
+ self.egg_output = os.path.join(self.dist_dir, basename + '.egg')
117
+
118
+ def do_install_data(self):
119
+ # Hack for packages that install data to install's --install-lib
120
+ self.get_finalized_command('install').install_lib = self.bdist_dir
121
+
122
+ site_packages = os.path.normcase(os.path.realpath(_get_purelib()))
123
+ old, self.distribution.data_files = self.distribution.data_files, []
124
+
125
+ for item in old:
126
+ if isinstance(item, tuple) and len(item) == 2:
127
+ if os.path.isabs(item[0]):
128
+ realpath = os.path.realpath(item[0])
129
+ normalized = os.path.normcase(realpath)
130
+ if normalized == site_packages or normalized.startswith(
131
+ site_packages + os.sep
132
+ ):
133
+ item = realpath[len(site_packages) + 1 :], item[1]
134
+ # XXX else: raise ???
135
+ self.distribution.data_files.append(item)
136
+
137
+ try:
138
+ log.info("installing package data to %s", self.bdist_dir)
139
+ self.call_command('install_data', force=False, root=None)
140
+ finally:
141
+ self.distribution.data_files = old
142
+
143
+ def get_outputs(self):
144
+ return [self.egg_output]
145
+
146
+ def call_command(self, cmdname, **kw):
147
+ """Invoke reinitialized command `cmdname` with keyword args"""
148
+ for dirname in INSTALL_DIRECTORY_ATTRS:
149
+ kw.setdefault(dirname, self.bdist_dir)
150
+ kw.setdefault('skip_build', self.skip_build)
151
+ kw.setdefault('dry_run', self.dry_run)
152
+ cmd = self.reinitialize_command(cmdname, **kw)
153
+ self.run_command(cmdname)
154
+ return cmd
155
+
156
+ def run(self): # noqa: C901 # is too complex (14) # FIXME
157
+ # Generate metadata first
158
+ self.run_command("egg_info")
159
+ # We run install_lib before install_data, because some data hacks
160
+ # pull their data path from the install_lib command.
161
+ log.info("installing library code to %s", self.bdist_dir)
162
+ instcmd = self.get_finalized_command('install')
163
+ old_root = instcmd.root
164
+ instcmd.root = None
165
+ if self.distribution.has_c_libraries() and not self.skip_build:
166
+ self.run_command('build_clib')
167
+ cmd = self.call_command('install_lib', warn_dir=False)
168
+ instcmd.root = old_root
169
+
170
+ all_outputs, ext_outputs = self.get_ext_outputs()
171
+ self.stubs = []
172
+ to_compile = []
173
+ for p, ext_name in enumerate(ext_outputs):
174
+ filename, ext = os.path.splitext(ext_name)
175
+ pyfile = os.path.join(self.bdist_dir, strip_module(filename) + '.py')
176
+ self.stubs.append(pyfile)
177
+ log.info("creating stub loader for %s", ext_name)
178
+ if not self.dry_run:
179
+ write_stub(os.path.basename(ext_name), pyfile)
180
+ to_compile.append(pyfile)
181
+ ext_outputs[p] = ext_name.replace(os.sep, '/')
182
+
183
+ if to_compile:
184
+ cmd.byte_compile(to_compile)
185
+ if self.distribution.data_files:
186
+ self.do_install_data()
187
+
188
+ # Make the EGG-INFO directory
189
+ archive_root = self.bdist_dir
190
+ egg_info = os.path.join(archive_root, 'EGG-INFO')
191
+ self.mkpath(egg_info)
192
+ if self.distribution.scripts:
193
+ script_dir = os.path.join(egg_info, 'scripts')
194
+ log.info("installing scripts to %s", script_dir)
195
+ self.call_command('install_scripts', install_dir=script_dir, no_ep=True)
196
+
197
+ self.copy_metadata_to(egg_info)
198
+ native_libs = os.path.join(egg_info, "native_libs.txt")
199
+ if all_outputs:
200
+ log.info("writing %s", native_libs)
201
+ if not self.dry_run:
202
+ ensure_directory(native_libs)
203
+ with open(native_libs, 'wt', encoding="utf-8") as libs_file:
204
+ libs_file.write('\n'.join(all_outputs))
205
+ libs_file.write('\n')
206
+ elif os.path.isfile(native_libs):
207
+ log.info("removing %s", native_libs)
208
+ if not self.dry_run:
209
+ os.unlink(native_libs)
210
+
211
+ write_safety_flag(os.path.join(archive_root, 'EGG-INFO'), self.zip_safe())
212
+
213
+ if os.path.exists(os.path.join(self.egg_info, 'depends.txt')):
214
+ log.warn(
215
+ "WARNING: 'depends.txt' will not be used by setuptools 0.6!\n"
216
+ "Use the install_requires/extras_require setup() args instead."
217
+ )
218
+
219
+ if self.exclude_source_files:
220
+ self.zap_pyfiles()
221
+
222
+ # Make the archive
223
+ make_zipfile(
224
+ self.egg_output,
225
+ archive_root,
226
+ verbose=self.verbose,
227
+ dry_run=self.dry_run,
228
+ mode=self.gen_header(),
229
+ )
230
+ if not self.keep_temp:
231
+ remove_tree(self.bdist_dir, dry_run=self.dry_run)
232
+
233
+ # Add to 'Distribution.dist_files' so that the "upload" command works
234
+ getattr(self.distribution, 'dist_files', []).append((
235
+ 'bdist_egg',
236
+ get_python_version(),
237
+ self.egg_output,
238
+ ))
239
+
240
+ def zap_pyfiles(self):
241
+ log.info("Removing .py files from temporary directory")
242
+ for base, dirs, files in walk_egg(self.bdist_dir):
243
+ for name in files:
244
+ path = os.path.join(base, name)
245
+
246
+ if name.endswith('.py'):
247
+ log.debug("Deleting %s", path)
248
+ os.unlink(path)
249
+
250
+ if base.endswith('__pycache__'):
251
+ path_old = path
252
+
253
+ pattern = r'(?P<name>.+)\.(?P<magic>[^.]+)\.pyc'
254
+ m = re.match(pattern, name)
255
+ path_new = os.path.join(base, os.pardir, m.group('name') + '.pyc')
256
+ log.info("Renaming file from [%s] to [%s]" % (path_old, path_new))
257
+ try:
258
+ os.remove(path_new)
259
+ except OSError:
260
+ pass
261
+ os.rename(path_old, path_new)
262
+
263
+ def zip_safe(self):
264
+ safe = getattr(self.distribution, 'zip_safe', None)
265
+ if safe is not None:
266
+ return safe
267
+ log.warn("zip_safe flag not set; analyzing archive contents...")
268
+ return analyze_egg(self.bdist_dir, self.stubs)
269
+
270
+ def gen_header(self):
271
+ return 'w'
272
+
273
+ def copy_metadata_to(self, target_dir):
274
+ "Copy metadata (egg info) to the target_dir"
275
+ # normalize the path (so that a forward-slash in egg_info will
276
+ # match using startswith below)
277
+ norm_egg_info = os.path.normpath(self.egg_info)
278
+ prefix = os.path.join(norm_egg_info, '')
279
+ for path in self.ei_cmd.filelist.files:
280
+ if path.startswith(prefix):
281
+ target = os.path.join(target_dir, path[len(prefix) :])
282
+ ensure_directory(target)
283
+ self.copy_file(path, target)
284
+
285
+ def get_ext_outputs(self):
286
+ """Get a list of relative paths to C extensions in the output distro"""
287
+
288
+ all_outputs = []
289
+ ext_outputs = []
290
+
291
+ paths = {self.bdist_dir: ''}
292
+ for base, dirs, files in sorted_walk(self.bdist_dir):
293
+ all_outputs.extend(
294
+ paths[base] + filename
295
+ for filename in files
296
+ if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS
297
+ )
298
+ for filename in dirs:
299
+ paths[os.path.join(base, filename)] = paths[base] + filename + '/'
300
+
301
+ if self.distribution.has_ext_modules():
302
+ build_cmd = self.get_finalized_command('build_ext')
303
+ for ext in build_cmd.extensions:
304
+ if isinstance(ext, Library):
305
+ continue
306
+ fullname = build_cmd.get_ext_fullname(ext.name)
307
+ filename = build_cmd.get_ext_filename(fullname)
308
+ if not os.path.basename(filename).startswith('dl-'):
309
+ if os.path.exists(os.path.join(self.bdist_dir, filename)):
310
+ ext_outputs.append(filename)
311
+
312
+ return all_outputs, ext_outputs
313
+
314
+
315
+ NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split())
316
+
317
+
318
+ def walk_egg(egg_dir):
319
+ """Walk an unpacked egg's contents, skipping the metadata directory"""
320
+ walker = sorted_walk(egg_dir)
321
+ base, dirs, files = next(walker)
322
+ if 'EGG-INFO' in dirs:
323
+ dirs.remove('EGG-INFO')
324
+ yield base, dirs, files
325
+ yield from walker
326
+
327
+
328
+ def analyze_egg(egg_dir, stubs):
329
+ # check for existing flag in EGG-INFO
330
+ for flag, fn in safety_flags.items():
331
+ if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)):
332
+ return flag
333
+ if not can_scan():
334
+ return False
335
+ safe = True
336
+ for base, dirs, files in walk_egg(egg_dir):
337
+ for name in files:
338
+ if name.endswith('.py') or name.endswith('.pyw'):
339
+ continue
340
+ elif name.endswith('.pyc') or name.endswith('.pyo'):
341
+ # always scan, even if we already know we're not safe
342
+ safe = scan_module(egg_dir, base, name, stubs) and safe
343
+ return safe
344
+
345
+
346
+ def write_safety_flag(egg_dir, safe):
347
+ # Write or remove zip safety flag file(s)
348
+ for flag, fn in safety_flags.items():
349
+ fn = os.path.join(egg_dir, fn)
350
+ if os.path.exists(fn):
351
+ if safe is None or bool(safe) != flag:
352
+ os.unlink(fn)
353
+ elif safe is not None and bool(safe) == flag:
354
+ with open(fn, 'wt', encoding="utf-8") as f:
355
+ f.write('\n')
356
+
357
+
358
+ safety_flags = {
359
+ True: 'zip-safe',
360
+ False: 'not-zip-safe',
361
+ }
362
+
363
+
364
+ def scan_module(egg_dir, base, name, stubs):
365
+ """Check whether module possibly uses unsafe-for-zipfile stuff"""
366
+
367
+ filename = os.path.join(base, name)
368
+ if filename[:-1] in stubs:
369
+ return True # Extension module
370
+ pkg = base[len(egg_dir) + 1 :].replace(os.sep, '.')
371
+ module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0]
372
+ skip = 16 # skip magic & reserved? & date & file size
373
+ f = open(filename, 'rb')
374
+ f.read(skip)
375
+ code = marshal.load(f)
376
+ f.close()
377
+ safe = True
378
+ symbols = dict.fromkeys(iter_symbols(code))
379
+ for bad in ['__file__', '__path__']:
380
+ if bad in symbols:
381
+ log.warn("%s: module references %s", module, bad)
382
+ safe = False
383
+ if 'inspect' in symbols:
384
+ for bad in [
385
+ 'getsource',
386
+ 'getabsfile',
387
+ 'getfile',
388
+ 'getsourcefile',
389
+ 'getsourcelines',
390
+ 'findsource',
391
+ 'getcomments',
392
+ 'getframeinfo',
393
+ 'getinnerframes',
394
+ 'getouterframes',
395
+ 'stack',
396
+ 'trace',
397
+ ]:
398
+ if bad in symbols:
399
+ log.warn("%s: module MAY be using inspect.%s", module, bad)
400
+ safe = False
401
+ return safe
402
+
403
+
404
+ def iter_symbols(code):
405
+ """Yield names and strings used by `code` and its nested code objects"""
406
+ yield from code.co_names
407
+ for const in code.co_consts:
408
+ if isinstance(const, str):
409
+ yield const
410
+ elif isinstance(const, CodeType):
411
+ yield from iter_symbols(const)
412
+
413
+
414
+ def can_scan():
415
+ if not sys.platform.startswith('java') and sys.platform != 'cli':
416
+ # CPython, PyPy, etc.
417
+ return True
418
+ log.warn("Unable to analyze compiled code on this platform.")
419
+ log.warn(
420
+ "Please ask the author to include a 'zip_safe'"
421
+ " setting (either True or False) in the package's setup.py"
422
+ )
423
+ return False
424
+
425
+
426
+ # Attribute names of options for commands that might need to be convinced to
427
+ # install to the egg build directory
428
+
429
+ INSTALL_DIRECTORY_ATTRS = ['install_lib', 'install_dir', 'install_data', 'install_base']
430
+
431
+
432
+ def make_zipfile(
433
+ zip_filename, base_dir, verbose=False, dry_run=False, compress=True, mode='w'
434
+ ):
435
+ """Create a zip file from all the files under 'base_dir'. The output
436
+ zip file will be named 'base_dir' + ".zip". Uses either the "zipfile"
437
+ Python module (if available) or the InfoZIP "zip" utility (if installed
438
+ and found on the default search path). If neither tool is available,
439
+ raises DistutilsExecError. Returns the name of the output zip file.
440
+ """
441
+ import zipfile
442
+
443
+ mkpath(os.path.dirname(zip_filename), dry_run=dry_run)
444
+ log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir)
445
+
446
+ def visit(z, dirname, names):
447
+ for name in names:
448
+ path = os.path.normpath(os.path.join(dirname, name))
449
+ if os.path.isfile(path):
450
+ p = path[len(base_dir) + 1 :]
451
+ if not dry_run:
452
+ z.write(path, p)
453
+ log.debug("adding '%s'", p)
454
+
455
+ compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED
456
+ if not dry_run:
457
+ z = zipfile.ZipFile(zip_filename, mode, compression=compression)
458
+ for dirname, dirs, files in sorted_walk(base_dir):
459
+ visit(z, dirname, files)
460
+ z.close()
461
+ else:
462
+ for dirname, dirs, files in sorted_walk(base_dir):
463
+ visit(None, dirname, files)
464
+ return zip_filename
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/bdist_rpm.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import distutils.command.bdist_rpm as orig
2
+
3
+ from ..warnings import SetuptoolsDeprecationWarning
4
+
5
+
6
+ class bdist_rpm(orig.bdist_rpm):
7
+ """
8
+ Override the default bdist_rpm behavior to do the following:
9
+
10
+ 1. Run egg_info to ensure the name and version are properly calculated.
11
+ 2. Always run 'install' using --single-version-externally-managed to
12
+ disable eggs in RPM distributions.
13
+ """
14
+
15
+ def run(self):
16
+ SetuptoolsDeprecationWarning.emit(
17
+ "Deprecated command",
18
+ """
19
+ bdist_rpm is deprecated and will be removed in a future version.
20
+ Use bdist_wheel (wheel packages) instead.
21
+ """,
22
+ see_url="https://github.com/pypa/setuptools/issues/1988",
23
+ due_date=(2023, 10, 30), # Deprecation introduced in 22 Oct 2021.
24
+ )
25
+
26
+ # ensure distro name is up-to-date
27
+ self.run_command('egg_info')
28
+
29
+ orig.bdist_rpm.run(self)
30
+
31
+ def _make_spec_file(self):
32
+ spec = orig.bdist_rpm._make_spec_file(self)
33
+ return [
34
+ line.replace(
35
+ "setup.py install ",
36
+ "setup.py install --single-version-externally-managed ",
37
+ ).replace("%setup", "%setup -n %{name}-%{unmangled_version}")
38
+ for line in spec
39
+ ]
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/bdist_wheel.py ADDED
@@ -0,0 +1,597 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Create a wheel (.whl) distribution.
3
+
4
+ A wheel is a built archive format.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ import re
11
+ import shutil
12
+ import stat
13
+ import struct
14
+ import sys
15
+ import sysconfig
16
+ import warnings
17
+ from email.generator import BytesGenerator, Generator
18
+ from email.policy import EmailPolicy
19
+ from distutils import log
20
+ from glob import iglob
21
+ from shutil import rmtree
22
+ from typing import TYPE_CHECKING, Callable, Iterable, Literal, Sequence, cast
23
+ from zipfile import ZIP_DEFLATED, ZIP_STORED
24
+
25
+ from .. import Command, __version__
26
+ from ..extern.wheel.metadata import pkginfo_to_metadata
27
+ from ..extern.packaging import tags
28
+ from ..extern.packaging import version as _packaging_version
29
+ from ..extern.wheel.wheelfile import WheelFile
30
+
31
+ if TYPE_CHECKING:
32
+ import types
33
+
34
+
35
+ def safe_name(name: str) -> str:
36
+ """Convert an arbitrary string to a standard distribution name
37
+ Any runs of non-alphanumeric/. characters are replaced with a single '-'.
38
+ """
39
+ return re.sub("[^A-Za-z0-9.]+", "-", name)
40
+
41
+
42
+ def safe_version(version: str) -> str:
43
+ """
44
+ Convert an arbitrary string to a standard version string
45
+ """
46
+ try:
47
+ # normalize the version
48
+ return str(_packaging_version.Version(version))
49
+ except _packaging_version.InvalidVersion:
50
+ version = version.replace(" ", ".")
51
+ return re.sub("[^A-Za-z0-9.]+", "-", version)
52
+
53
+
54
+ setuptools_major_version = int(__version__.split(".")[0])
55
+
56
+ PY_LIMITED_API_PATTERN = r"cp3\d"
57
+
58
+
59
+ def _is_32bit_interpreter() -> bool:
60
+ return struct.calcsize("P") == 4
61
+
62
+
63
+ def python_tag() -> str:
64
+ return f"py{sys.version_info[0]}"
65
+
66
+
67
+ def get_platform(archive_root: str | None) -> str:
68
+ """Return our platform name 'win32', 'linux_x86_64'"""
69
+ result = sysconfig.get_platform()
70
+ if result.startswith("macosx") and archive_root is not None:
71
+ from ..extern.wheel.macosx_libfile import calculate_macosx_platform_tag
72
+
73
+ result = calculate_macosx_platform_tag(archive_root, result)
74
+ elif _is_32bit_interpreter():
75
+ if result == "linux-x86_64":
76
+ # pip pull request #3497
77
+ result = "linux-i686"
78
+ elif result == "linux-aarch64":
79
+ # packaging pull request #234
80
+ # TODO armv8l, packaging pull request #690 => this did not land
81
+ # in pip/packaging yet
82
+ result = "linux-armv7l"
83
+
84
+ return result.replace("-", "_")
85
+
86
+
87
+ def get_flag(
88
+ var: str, fallback: bool, expected: bool = True, warn: bool = True
89
+ ) -> bool:
90
+ """Use a fallback value for determining SOABI flags if the needed config
91
+ var is unset or unavailable."""
92
+ val = sysconfig.get_config_var(var)
93
+ if val is None:
94
+ if warn:
95
+ warnings.warn(
96
+ f"Config variable '{var}' is unset, Python ABI tag may be incorrect",
97
+ RuntimeWarning,
98
+ stacklevel=2,
99
+ )
100
+ return fallback
101
+ return val == expected
102
+
103
+
104
+ def get_abi_tag() -> str | None:
105
+ """Return the ABI tag based on SOABI (if available) or emulate SOABI (PyPy2)."""
106
+ soabi: str = sysconfig.get_config_var("SOABI")
107
+ impl = tags.interpreter_name()
108
+ if not soabi and impl in ("cp", "pp") and hasattr(sys, "maxunicode"):
109
+ d = ""
110
+ m = ""
111
+ u = ""
112
+ if get_flag("Py_DEBUG", hasattr(sys, "gettotalrefcount"), warn=(impl == "cp")):
113
+ d = "d"
114
+
115
+ if get_flag(
116
+ "WITH_PYMALLOC",
117
+ impl == "cp",
118
+ warn=(impl == "cp" and sys.version_info < (3, 8)),
119
+ ) and sys.version_info < (3, 8):
120
+ m = "m"
121
+
122
+ abi = f"{impl}{tags.interpreter_version()}{d}{m}{u}"
123
+ elif soabi and impl == "cp" and soabi.startswith("cpython"):
124
+ # non-Windows
125
+ abi = "cp" + soabi.split("-")[1]
126
+ elif soabi and impl == "cp" and soabi.startswith("cp"):
127
+ # Windows
128
+ abi = soabi.split("-")[0]
129
+ elif soabi and impl == "pp":
130
+ # we want something like pypy36-pp73
131
+ abi = "-".join(soabi.split("-")[:2])
132
+ abi = abi.replace(".", "_").replace("-", "_")
133
+ elif soabi and impl == "graalpy":
134
+ abi = "-".join(soabi.split("-")[:3])
135
+ abi = abi.replace(".", "_").replace("-", "_")
136
+ elif soabi:
137
+ abi = soabi.replace(".", "_").replace("-", "_")
138
+ else:
139
+ abi = None
140
+
141
+ return abi
142
+
143
+
144
+ def safer_name(name: str) -> str:
145
+ return safe_name(name).replace("-", "_")
146
+
147
+
148
+ def safer_version(version: str) -> str:
149
+ return safe_version(version).replace("-", "_")
150
+
151
+
152
+ def remove_readonly(
153
+ func: Callable[..., object],
154
+ path: str,
155
+ excinfo: tuple[type[Exception], Exception, types.TracebackType],
156
+ ) -> None:
157
+ remove_readonly_exc(func, path, excinfo[1])
158
+
159
+
160
+ def remove_readonly_exc(func: Callable[..., object], path: str, exc: Exception) -> None:
161
+ os.chmod(path, stat.S_IWRITE)
162
+ func(path)
163
+
164
+
165
+ class bdist_wheel(Command):
166
+ description = "create a wheel distribution"
167
+
168
+ supported_compressions = {
169
+ "stored": ZIP_STORED,
170
+ "deflated": ZIP_DEFLATED,
171
+ }
172
+
173
+ user_options = [
174
+ ("bdist-dir=", "b", "temporary directory for creating the distribution"),
175
+ (
176
+ "plat-name=",
177
+ "p",
178
+ "platform name to embed in generated filenames "
179
+ f"[default: {get_platform(None)}]",
180
+ ),
181
+ (
182
+ "keep-temp",
183
+ "k",
184
+ "keep the pseudo-installation tree around after "
185
+ "creating the distribution archive",
186
+ ),
187
+ ("dist-dir=", "d", "directory to put final built distributions in"),
188
+ ("skip-build", None, "skip rebuilding everything (for testing/debugging)"),
189
+ (
190
+ "relative",
191
+ None,
192
+ "build the archive using relative paths [default: false]",
193
+ ),
194
+ (
195
+ "owner=",
196
+ "u",
197
+ "Owner name used when creating a tar file [default: current user]",
198
+ ),
199
+ (
200
+ "group=",
201
+ "g",
202
+ "Group name used when creating a tar file [default: current group]",
203
+ ),
204
+ ("universal", None, "make a universal wheel [default: false]"),
205
+ (
206
+ "compression=",
207
+ None,
208
+ "zipfile compression (one of: {}) [default: 'deflated']".format(
209
+ ", ".join(supported_compressions)
210
+ ),
211
+ ),
212
+ (
213
+ "python-tag=",
214
+ None,
215
+ f"Python implementation compatibility tag [default: '{python_tag()}']",
216
+ ),
217
+ (
218
+ "build-number=",
219
+ None,
220
+ "Build number for this particular version. "
221
+ "As specified in PEP-0427, this must start with a digit. "
222
+ "[default: None]",
223
+ ),
224
+ (
225
+ "py-limited-api=",
226
+ None,
227
+ "Python tag (cp32|cp33|cpNN) for abi3 wheel tag [default: false]",
228
+ ),
229
+ ]
230
+
231
+ boolean_options = ["keep-temp", "skip-build", "relative", "universal"]
232
+
233
+ def initialize_options(self) -> None:
234
+ self.bdist_dir: str | None = None
235
+ self.data_dir = None
236
+ self.plat_name: str | None = None
237
+ self.plat_tag = None
238
+ self.format = "zip"
239
+ self.keep_temp = False
240
+ self.dist_dir: str | None = None
241
+ self.egginfo_dir = None
242
+ self.root_is_pure: bool | None = None
243
+ self.skip_build = None
244
+ self.relative = False
245
+ self.owner = None
246
+ self.group = None
247
+ self.universal: bool = False
248
+ self.compression: str | int = "deflated"
249
+ self.python_tag: str = python_tag()
250
+ self.build_number: str | None = None
251
+ self.py_limited_api: str | Literal[False] = False
252
+ self.plat_name_supplied = False
253
+
254
+ def finalize_options(self):
255
+ if self.bdist_dir is None:
256
+ bdist_base = self.get_finalized_command("bdist").bdist_base
257
+ self.bdist_dir = os.path.join(bdist_base, "wheel")
258
+
259
+ egg_info = self.distribution.get_command_obj("egg_info")
260
+ egg_info.ensure_finalized() # needed for correct `wheel_dist_name`
261
+
262
+ self.data_dir = self.wheel_dist_name + ".data"
263
+ self.plat_name_supplied = self.plat_name is not None
264
+
265
+ try:
266
+ self.compression = self.supported_compressions[self.compression]
267
+ except KeyError:
268
+ raise ValueError(f"Unsupported compression: {self.compression}") from None
269
+
270
+ need_options = ("dist_dir", "plat_name", "skip_build")
271
+
272
+ self.set_undefined_options("bdist", *zip(need_options, need_options))
273
+
274
+ self.root_is_pure = not (
275
+ self.distribution.has_ext_modules() or self.distribution.has_c_libraries()
276
+ )
277
+
278
+ if self.py_limited_api and not re.match(
279
+ PY_LIMITED_API_PATTERN, self.py_limited_api
280
+ ):
281
+ raise ValueError(f"py-limited-api must match '{PY_LIMITED_API_PATTERN}'")
282
+
283
+ # Support legacy [wheel] section for setting universal
284
+ wheel = self.distribution.get_option_dict("wheel")
285
+ if "universal" in wheel:
286
+ # please don't define this in your global configs
287
+ log.warn("The [wheel] section is deprecated. Use [bdist_wheel] instead.")
288
+ val = wheel["universal"][1].strip()
289
+ if val.lower() in ("1", "true", "yes"):
290
+ self.universal = True
291
+
292
+ if self.build_number is not None and not self.build_number[:1].isdigit():
293
+ raise ValueError("Build tag (build-number) must start with a digit.")
294
+
295
+ @property
296
+ def wheel_dist_name(self):
297
+ """Return distribution full name with - replaced with _"""
298
+ components = (
299
+ safer_name(self.distribution.get_name()),
300
+ safer_version(self.distribution.get_version()),
301
+ )
302
+ if self.build_number:
303
+ components += (self.build_number,)
304
+ return "-".join(components)
305
+
306
+ def get_tag(self) -> tuple[str, str, str]:
307
+ # bdist sets self.plat_name if unset, we should only use it for purepy
308
+ # wheels if the user supplied it.
309
+ if self.plat_name_supplied:
310
+ plat_name = cast(str, self.plat_name)
311
+ elif self.root_is_pure:
312
+ plat_name = "any"
313
+ else:
314
+ # macosx contains system version in platform name so need special handle
315
+ if self.plat_name and not self.plat_name.startswith("macosx"):
316
+ plat_name = self.plat_name
317
+ else:
318
+ # on macosx always limit the platform name to comply with any
319
+ # c-extension modules in bdist_dir, since the user can specify
320
+ # a higher MACOSX_DEPLOYMENT_TARGET via tools like CMake
321
+
322
+ # on other platforms, and on macosx if there are no c-extension
323
+ # modules, use the default platform name.
324
+ plat_name = get_platform(self.bdist_dir)
325
+
326
+ if _is_32bit_interpreter():
327
+ if plat_name in ("linux-x86_64", "linux_x86_64"):
328
+ plat_name = "linux_i686"
329
+ if plat_name in ("linux-aarch64", "linux_aarch64"):
330
+ # TODO armv8l, packaging pull request #690 => this did not land
331
+ # in pip/packaging yet
332
+ plat_name = "linux_armv7l"
333
+
334
+ plat_name = (
335
+ plat_name.lower().replace("-", "_").replace(".", "_").replace(" ", "_")
336
+ )
337
+
338
+ if self.root_is_pure:
339
+ if self.universal:
340
+ impl = "py2.py3"
341
+ else:
342
+ impl = self.python_tag
343
+ tag = (impl, "none", plat_name)
344
+ else:
345
+ impl_name = tags.interpreter_name()
346
+ impl_ver = tags.interpreter_version()
347
+ impl = impl_name + impl_ver
348
+ # We don't work on CPython 3.1, 3.0.
349
+ if self.py_limited_api and (impl_name + impl_ver).startswith("cp3"):
350
+ impl = self.py_limited_api
351
+ abi_tag = "abi3"
352
+ else:
353
+ abi_tag = str(get_abi_tag()).lower()
354
+ tag = (impl, abi_tag, plat_name)
355
+ # issue gh-374: allow overriding plat_name
356
+ supported_tags = [
357
+ (t.interpreter, t.abi, plat_name) for t in tags.sys_tags()
358
+ ]
359
+ assert (
360
+ tag in supported_tags
361
+ ), f"would build wheel with unsupported tag {tag}"
362
+ return tag
363
+
364
+ def run(self):
365
+ build_scripts = self.reinitialize_command("build_scripts")
366
+ build_scripts.executable = "python"
367
+ build_scripts.force = True
368
+
369
+ build_ext = self.reinitialize_command("build_ext")
370
+ build_ext.inplace = False
371
+
372
+ if not self.skip_build:
373
+ self.run_command("build")
374
+
375
+ install = self.reinitialize_command("install", reinit_subcommands=True)
376
+ install.root = self.bdist_dir
377
+ install.compile = False
378
+ install.skip_build = self.skip_build
379
+ install.warn_dir = False
380
+
381
+ # A wheel without setuptools scripts is more cross-platform.
382
+ # Use the (undocumented) `no_ep` option to setuptools'
383
+ # install_scripts command to avoid creating entry point scripts.
384
+ install_scripts = self.reinitialize_command("install_scripts")
385
+ install_scripts.no_ep = True
386
+
387
+ # Use a custom scheme for the archive, because we have to decide
388
+ # at installation time which scheme to use.
389
+ for key in ("headers", "scripts", "data", "purelib", "platlib"):
390
+ setattr(install, "install_" + key, os.path.join(self.data_dir, key))
391
+
392
+ basedir_observed = ""
393
+
394
+ if os.name == "nt":
395
+ # win32 barfs if any of these are ''; could be '.'?
396
+ # (distutils.command.install:change_roots bug)
397
+ basedir_observed = os.path.normpath(os.path.join(self.data_dir, ".."))
398
+ self.install_libbase = self.install_lib = basedir_observed
399
+
400
+ setattr(
401
+ install,
402
+ "install_purelib" if self.root_is_pure else "install_platlib",
403
+ basedir_observed,
404
+ )
405
+
406
+ log.info(f"installing to {self.bdist_dir}")
407
+
408
+ self.run_command("install")
409
+
410
+ impl_tag, abi_tag, plat_tag = self.get_tag()
411
+ archive_basename = f"{self.wheel_dist_name}-{impl_tag}-{abi_tag}-{plat_tag}"
412
+ if not self.relative:
413
+ archive_root = self.bdist_dir
414
+ else:
415
+ archive_root = os.path.join(
416
+ self.bdist_dir, self._ensure_relative(install.install_base)
417
+ )
418
+
419
+ self.set_undefined_options("install_egg_info", ("target", "egginfo_dir"))
420
+ distinfo_dirname = (
421
+ f"{safer_name(self.distribution.get_name())}-"
422
+ f"{safer_version(self.distribution.get_version())}.dist-info"
423
+ )
424
+ distinfo_dir = os.path.join(self.bdist_dir, distinfo_dirname)
425
+ self.egg2dist(self.egginfo_dir, distinfo_dir)
426
+
427
+ self.write_wheelfile(distinfo_dir)
428
+
429
+ # Make the archive
430
+ if not os.path.exists(self.dist_dir):
431
+ os.makedirs(self.dist_dir)
432
+
433
+ wheel_path = os.path.join(self.dist_dir, archive_basename + ".whl")
434
+ with WheelFile(wheel_path, "w", self.compression) as wf:
435
+ wf.write_files(archive_root)
436
+
437
+ # Add to 'Distribution.dist_files' so that the "upload" command works
438
+ getattr(self.distribution, "dist_files", []).append((
439
+ "bdist_wheel",
440
+ "{}.{}".format(*sys.version_info[:2]), # like 3.7
441
+ wheel_path,
442
+ ))
443
+
444
+ if not self.keep_temp:
445
+ log.info(f"removing {self.bdist_dir}")
446
+ if not self.dry_run:
447
+ if sys.version_info < (3, 12):
448
+ rmtree(self.bdist_dir, onerror=remove_readonly)
449
+ else:
450
+ rmtree(self.bdist_dir, onexc=remove_readonly_exc)
451
+
452
+ def write_wheelfile(
453
+ self, wheelfile_base: str, generator: str = f"setuptools ({__version__})"
454
+ ):
455
+ from email.message import Message
456
+
457
+ msg = Message()
458
+ msg["Wheel-Version"] = "1.0" # of the spec
459
+ msg["Generator"] = generator
460
+ msg["Root-Is-Purelib"] = str(self.root_is_pure).lower()
461
+ if self.build_number is not None:
462
+ msg["Build"] = self.build_number
463
+
464
+ # Doesn't work for bdist_wininst
465
+ impl_tag, abi_tag, plat_tag = self.get_tag()
466
+ for impl in impl_tag.split("."):
467
+ for abi in abi_tag.split("."):
468
+ for plat in plat_tag.split("."):
469
+ msg["Tag"] = "-".join((impl, abi, plat))
470
+
471
+ wheelfile_path = os.path.join(wheelfile_base, "WHEEL")
472
+ log.info(f"creating {wheelfile_path}")
473
+ with open(wheelfile_path, "wb") as f:
474
+ BytesGenerator(f, maxheaderlen=0).flatten(msg)
475
+
476
+ def _ensure_relative(self, path: str) -> str:
477
+ # copied from dir_util, deleted
478
+ drive, path = os.path.splitdrive(path)
479
+ if path[0:1] == os.sep:
480
+ path = drive + path[1:]
481
+ return path
482
+
483
+ @property
484
+ def license_paths(self) -> Iterable[str]:
485
+ if setuptools_major_version >= 57:
486
+ # Setuptools has resolved any patterns to actual file names
487
+ return self.distribution.metadata.license_files or ()
488
+
489
+ files: set[str] = set()
490
+ metadata = self.distribution.get_option_dict("metadata")
491
+ if setuptools_major_version >= 42:
492
+ # Setuptools recognizes the license_files option but does not do globbing
493
+ patterns = cast(Sequence[str], self.distribution.metadata.license_files)
494
+ else:
495
+ # Prior to those, wheel is entirely responsible for handling license files
496
+ if "license_files" in metadata:
497
+ patterns = metadata["license_files"][1].split()
498
+ else:
499
+ patterns = ()
500
+
501
+ if "license_file" in metadata:
502
+ warnings.warn(
503
+ 'The "license_file" option is deprecated. Use "license_files" instead.',
504
+ DeprecationWarning,
505
+ stacklevel=2,
506
+ )
507
+ files.add(metadata["license_file"][1])
508
+
509
+ if not files and not patterns and not isinstance(patterns, list):
510
+ patterns = ("LICEN[CS]E*", "COPYING*", "NOTICE*", "AUTHORS*")
511
+
512
+ for pattern in patterns:
513
+ for path in iglob(pattern):
514
+ if path.endswith("~"):
515
+ log.debug(
516
+ f'ignoring license file "{path}" as it looks like a backup'
517
+ )
518
+ continue
519
+
520
+ if path not in files and os.path.isfile(path):
521
+ log.info(
522
+ f'adding license file "{path}" (matched pattern "{pattern}")'
523
+ )
524
+ files.add(path)
525
+
526
+ return files
527
+
528
+ def egg2dist(self, egginfo_path: str, distinfo_path: str):
529
+ """Convert an .egg-info directory into a .dist-info directory"""
530
+
531
+ def adios(p: str) -> None:
532
+ """Appropriately delete directory, file or link."""
533
+ if os.path.exists(p) and not os.path.islink(p) and os.path.isdir(p):
534
+ shutil.rmtree(p)
535
+ elif os.path.exists(p):
536
+ os.unlink(p)
537
+
538
+ adios(distinfo_path)
539
+
540
+ if not os.path.exists(egginfo_path):
541
+ # There is no egg-info. This is probably because the egg-info
542
+ # file/directory is not named matching the distribution name used
543
+ # to name the archive file. Check for this case and report
544
+ # accordingly.
545
+ import glob
546
+
547
+ pat = os.path.join(os.path.dirname(egginfo_path), "*.egg-info")
548
+ possible = glob.glob(pat)
549
+ err = f"Egg metadata expected at {egginfo_path} but not found"
550
+ if possible:
551
+ alt = os.path.basename(possible[0])
552
+ err += f" ({alt} found - possible misnamed archive file?)"
553
+
554
+ raise ValueError(err)
555
+
556
+ if os.path.isfile(egginfo_path):
557
+ # .egg-info is a single file
558
+ pkg_info = pkginfo_to_metadata(egginfo_path, egginfo_path)
559
+ os.mkdir(distinfo_path)
560
+ else:
561
+ # .egg-info is a directory
562
+ pkginfo_path = os.path.join(egginfo_path, "PKG-INFO")
563
+ pkg_info = pkginfo_to_metadata(egginfo_path, pkginfo_path)
564
+
565
+ # ignore common egg metadata that is useless to wheel
566
+ shutil.copytree(
567
+ egginfo_path,
568
+ distinfo_path,
569
+ ignore=lambda x, y: {
570
+ "PKG-INFO",
571
+ "requires.txt",
572
+ "SOURCES.txt",
573
+ "not-zip-safe",
574
+ },
575
+ )
576
+
577
+ # delete dependency_links if it is only whitespace
578
+ dependency_links_path = os.path.join(distinfo_path, "dependency_links.txt")
579
+ with open(dependency_links_path, encoding="utf-8") as dependency_links_file:
580
+ dependency_links = dependency_links_file.read().strip()
581
+ if not dependency_links:
582
+ adios(dependency_links_path)
583
+
584
+ pkg_info_path = os.path.join(distinfo_path, "METADATA")
585
+ serialization_policy = EmailPolicy(
586
+ utf8=True,
587
+ mangle_from_=False,
588
+ max_line_length=0,
589
+ )
590
+ with open(pkg_info_path, "w", encoding="utf-8") as out:
591
+ Generator(out, policy=serialization_policy).flatten(pkg_info)
592
+
593
+ for license_path in self.license_paths:
594
+ filename = os.path.basename(license_path)
595
+ shutil.copy(license_path, os.path.join(distinfo_path, filename))
596
+
597
+ adios(egginfo_path)
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/build_py.py ADDED
@@ -0,0 +1,401 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from functools import partial
4
+ from glob import glob
5
+ from distutils.util import convert_path
6
+ import distutils.command.build_py as orig
7
+ import os
8
+ import fnmatch
9
+ import textwrap
10
+ import distutils.errors
11
+ import itertools
12
+ import stat
13
+ from pathlib import Path
14
+ from typing import Iterable, Iterator
15
+
16
+ from ..extern.more_itertools import unique_everseen
17
+ from ..warnings import SetuptoolsDeprecationWarning
18
+
19
+
20
+ _IMPLICIT_DATA_FILES = ('*.pyi', 'py.typed')
21
+
22
+
23
+ def make_writable(target):
24
+ os.chmod(target, os.stat(target).st_mode | stat.S_IWRITE)
25
+
26
+
27
+ class build_py(orig.build_py):
28
+ """Enhanced 'build_py' command that includes data files with packages
29
+
30
+ The data files are specified via a 'package_data' argument to 'setup()'.
31
+ See 'setuptools.dist.Distribution' for more details.
32
+
33
+ Also, this version of the 'build_py' command allows you to specify both
34
+ 'py_modules' and 'packages' in the same setup operation.
35
+ """
36
+
37
+ editable_mode: bool = False
38
+ existing_egg_info_dir: str | None = None #: Private API, internal use only.
39
+
40
+ def finalize_options(self):
41
+ orig.build_py.finalize_options(self)
42
+ self.package_data = self.distribution.package_data
43
+ self.exclude_package_data = self.distribution.exclude_package_data or {}
44
+ if 'data_files' in self.__dict__:
45
+ del self.__dict__['data_files']
46
+ self.__updated_files = []
47
+
48
+ def copy_file(
49
+ self,
50
+ infile,
51
+ outfile,
52
+ preserve_mode=True,
53
+ preserve_times=True,
54
+ link=None,
55
+ level=1,
56
+ ):
57
+ # Overwrite base class to allow using links
58
+ if link:
59
+ infile = str(Path(infile).resolve())
60
+ outfile = str(Path(outfile).resolve())
61
+ return super().copy_file(
62
+ infile, outfile, preserve_mode, preserve_times, link, level
63
+ )
64
+
65
+ def run(self):
66
+ """Build modules, packages, and copy data files to build directory"""
67
+ if not (self.py_modules or self.packages) or self.editable_mode:
68
+ return
69
+
70
+ if self.py_modules:
71
+ self.build_modules()
72
+
73
+ if self.packages:
74
+ self.build_packages()
75
+ self.build_package_data()
76
+
77
+ # Only compile actual .py files, using our base class' idea of what our
78
+ # output files are.
79
+ self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=False))
80
+
81
+ def __getattr__(self, attr):
82
+ "lazily compute data files"
83
+ if attr == 'data_files':
84
+ self.data_files = self._get_data_files()
85
+ return self.data_files
86
+ return orig.build_py.__getattr__(self, attr)
87
+
88
+ def build_module(self, module, module_file, package):
89
+ outfile, copied = orig.build_py.build_module(self, module, module_file, package)
90
+ if copied:
91
+ self.__updated_files.append(outfile)
92
+ return outfile, copied
93
+
94
+ def _get_data_files(self):
95
+ """Generate list of '(package,src_dir,build_dir,filenames)' tuples"""
96
+ self.analyze_manifest()
97
+ return list(map(self._get_pkg_data_files, self.packages or ()))
98
+
99
+ def get_data_files_without_manifest(self):
100
+ """
101
+ Generate list of ``(package,src_dir,build_dir,filenames)`` tuples,
102
+ but without triggering any attempt to analyze or build the manifest.
103
+ """
104
+ # Prevent eventual errors from unset `manifest_files`
105
+ # (that would otherwise be set by `analyze_manifest`)
106
+ self.__dict__.setdefault('manifest_files', {})
107
+ return list(map(self._get_pkg_data_files, self.packages or ()))
108
+
109
+ def _get_pkg_data_files(self, package):
110
+ # Locate package source directory
111
+ src_dir = self.get_package_dir(package)
112
+
113
+ # Compute package build directory
114
+ build_dir = os.path.join(*([self.build_lib] + package.split('.')))
115
+
116
+ # Strip directory from globbed filenames
117
+ filenames = [
118
+ os.path.relpath(file, src_dir)
119
+ for file in self.find_data_files(package, src_dir)
120
+ ]
121
+ return package, src_dir, build_dir, filenames
122
+
123
+ def find_data_files(self, package, src_dir):
124
+ """Return filenames for package's data files in 'src_dir'"""
125
+ patterns = self._get_platform_patterns(
126
+ self.package_data,
127
+ package,
128
+ src_dir,
129
+ extra_patterns=_IMPLICIT_DATA_FILES,
130
+ )
131
+ globs_expanded = map(partial(glob, recursive=True), patterns)
132
+ # flatten the expanded globs into an iterable of matches
133
+ globs_matches = itertools.chain.from_iterable(globs_expanded)
134
+ glob_files = filter(os.path.isfile, globs_matches)
135
+ files = itertools.chain(
136
+ self.manifest_files.get(package, []),
137
+ glob_files,
138
+ )
139
+ return self.exclude_data_files(package, src_dir, files)
140
+
141
+ def get_outputs(self, include_bytecode=True) -> list[str]:
142
+ """See :class:`setuptools.commands.build.SubCommand`"""
143
+ if self.editable_mode:
144
+ return list(self.get_output_mapping().keys())
145
+ return super().get_outputs(include_bytecode)
146
+
147
+ def get_output_mapping(self) -> dict[str, str]:
148
+ """See :class:`setuptools.commands.build.SubCommand`"""
149
+ mapping = itertools.chain(
150
+ self._get_package_data_output_mapping(),
151
+ self._get_module_mapping(),
152
+ )
153
+ return dict(sorted(mapping, key=lambda x: x[0]))
154
+
155
+ def _get_module_mapping(self) -> Iterator[tuple[str, str]]:
156
+ """Iterate over all modules producing (dest, src) pairs."""
157
+ for package, module, module_file in self.find_all_modules():
158
+ package = package.split('.')
159
+ filename = self.get_module_outfile(self.build_lib, package, module)
160
+ yield (filename, module_file)
161
+
162
+ def _get_package_data_output_mapping(self) -> Iterator[tuple[str, str]]:
163
+ """Iterate over package data producing (dest, src) pairs."""
164
+ for package, src_dir, build_dir, filenames in self.data_files:
165
+ for filename in filenames:
166
+ target = os.path.join(build_dir, filename)
167
+ srcfile = os.path.join(src_dir, filename)
168
+ yield (target, srcfile)
169
+
170
+ def build_package_data(self):
171
+ """Copy data files into build directory"""
172
+ for target, srcfile in self._get_package_data_output_mapping():
173
+ self.mkpath(os.path.dirname(target))
174
+ _outf, _copied = self.copy_file(srcfile, target)
175
+ make_writable(target)
176
+
177
+ def analyze_manifest(self):
178
+ self.manifest_files = mf = {}
179
+ if not self.distribution.include_package_data:
180
+ return
181
+ src_dirs = {}
182
+ for package in self.packages or ():
183
+ # Locate package source directory
184
+ src_dirs[assert_relative(self.get_package_dir(package))] = package
185
+
186
+ if (
187
+ getattr(self, 'existing_egg_info_dir', None)
188
+ and Path(self.existing_egg_info_dir, "SOURCES.txt").exists()
189
+ ):
190
+ egg_info_dir = self.existing_egg_info_dir
191
+ manifest = Path(egg_info_dir, "SOURCES.txt")
192
+ files = manifest.read_text(encoding="utf-8").splitlines()
193
+ else:
194
+ self.run_command('egg_info')
195
+ ei_cmd = self.get_finalized_command('egg_info')
196
+ egg_info_dir = ei_cmd.egg_info
197
+ files = ei_cmd.filelist.files
198
+
199
+ check = _IncludePackageDataAbuse()
200
+ for path in self._filter_build_files(files, egg_info_dir):
201
+ d, f = os.path.split(assert_relative(path))
202
+ prev = None
203
+ oldf = f
204
+ while d and d != prev and d not in src_dirs:
205
+ prev = d
206
+ d, df = os.path.split(d)
207
+ f = os.path.join(df, f)
208
+ if d in src_dirs:
209
+ if f == oldf:
210
+ if check.is_module(f):
211
+ continue # it's a module, not data
212
+ else:
213
+ importable = check.importable_subpackage(src_dirs[d], f)
214
+ if importable:
215
+ check.warn(importable)
216
+ mf.setdefault(src_dirs[d], []).append(path)
217
+
218
+ def _filter_build_files(self, files: Iterable[str], egg_info: str) -> Iterator[str]:
219
+ """
220
+ ``build_meta`` may try to create egg_info outside of the project directory,
221
+ and this can be problematic for certain plugins (reported in issue #3500).
222
+
223
+ Extensions might also include between their sources files created on the
224
+ ``build_lib`` and ``build_temp`` directories.
225
+
226
+ This function should filter this case of invalid files out.
227
+ """
228
+ build = self.get_finalized_command("build")
229
+ build_dirs = (egg_info, self.build_lib, build.build_temp, build.build_base)
230
+ norm_dirs = [os.path.normpath(p) for p in build_dirs if p]
231
+
232
+ for file in files:
233
+ norm_path = os.path.normpath(file)
234
+ if not os.path.isabs(file) or all(d not in norm_path for d in norm_dirs):
235
+ yield file
236
+
237
+ def get_data_files(self):
238
+ pass # Lazily compute data files in _get_data_files() function.
239
+
240
+ def check_package(self, package, package_dir):
241
+ """Check namespace packages' __init__ for declare_namespace"""
242
+ try:
243
+ return self.packages_checked[package]
244
+ except KeyError:
245
+ pass
246
+
247
+ init_py = orig.build_py.check_package(self, package, package_dir)
248
+ self.packages_checked[package] = init_py
249
+
250
+ if not init_py or not self.distribution.namespace_packages:
251
+ return init_py
252
+
253
+ for pkg in self.distribution.namespace_packages:
254
+ if pkg == package or pkg.startswith(package + '.'):
255
+ break
256
+ else:
257
+ return init_py
258
+
259
+ with open(init_py, 'rb') as f:
260
+ contents = f.read()
261
+ if b'declare_namespace' not in contents:
262
+ raise distutils.errors.DistutilsError(
263
+ "Namespace package problem: %s is a namespace package, but "
264
+ "its\n__init__.py does not call declare_namespace()! Please "
265
+ 'fix it.\n(See the setuptools manual under '
266
+ '"Namespace Packages" for details.)\n"' % (package,)
267
+ )
268
+ return init_py
269
+
270
+ def initialize_options(self):
271
+ self.packages_checked = {}
272
+ orig.build_py.initialize_options(self)
273
+ self.editable_mode = False
274
+ self.existing_egg_info_dir = None
275
+
276
+ def get_package_dir(self, package):
277
+ res = orig.build_py.get_package_dir(self, package)
278
+ if self.distribution.src_root is not None:
279
+ return os.path.join(self.distribution.src_root, res)
280
+ return res
281
+
282
+ def exclude_data_files(self, package, src_dir, files):
283
+ """Filter filenames for package's data files in 'src_dir'"""
284
+ files = list(files)
285
+ patterns = self._get_platform_patterns(
286
+ self.exclude_package_data,
287
+ package,
288
+ src_dir,
289
+ )
290
+ match_groups = (fnmatch.filter(files, pattern) for pattern in patterns)
291
+ # flatten the groups of matches into an iterable of matches
292
+ matches = itertools.chain.from_iterable(match_groups)
293
+ bad = set(matches)
294
+ keepers = (fn for fn in files if fn not in bad)
295
+ # ditch dupes
296
+ return list(unique_everseen(keepers))
297
+
298
+ @staticmethod
299
+ def _get_platform_patterns(spec, package, src_dir, extra_patterns=()):
300
+ """
301
+ yield platform-specific path patterns (suitable for glob
302
+ or fn_match) from a glob-based spec (such as
303
+ self.package_data or self.exclude_package_data)
304
+ matching package in src_dir.
305
+ """
306
+ raw_patterns = itertools.chain(
307
+ extra_patterns,
308
+ spec.get('', []),
309
+ spec.get(package, []),
310
+ )
311
+ return (
312
+ # Each pattern has to be converted to a platform-specific path
313
+ os.path.join(src_dir, convert_path(pattern))
314
+ for pattern in raw_patterns
315
+ )
316
+
317
+
318
+ def assert_relative(path):
319
+ if not os.path.isabs(path):
320
+ return path
321
+ from distutils.errors import DistutilsSetupError
322
+
323
+ msg = (
324
+ textwrap.dedent(
325
+ """
326
+ Error: setup script specifies an absolute path:
327
+
328
+ %s
329
+
330
+ setup() arguments must *always* be /-separated paths relative to the
331
+ setup.py directory, *never* absolute paths.
332
+ """
333
+ ).lstrip()
334
+ % path
335
+ )
336
+ raise DistutilsSetupError(msg)
337
+
338
+
339
+ class _IncludePackageDataAbuse:
340
+ """Inform users that package or module is included as 'data file'"""
341
+
342
+ class _Warning(SetuptoolsDeprecationWarning):
343
+ _SUMMARY = """
344
+ Package {importable!r} is absent from the `packages` configuration.
345
+ """
346
+
347
+ _DETAILS = """
348
+ ############################
349
+ # Package would be ignored #
350
+ ############################
351
+ Python recognizes {importable!r} as an importable package[^1],
352
+ but it is absent from setuptools' `packages` configuration.
353
+
354
+ This leads to an ambiguous overall configuration. If you want to distribute this
355
+ package, please make sure that {importable!r} is explicitly added
356
+ to the `packages` configuration field.
357
+
358
+ Alternatively, you can also rely on setuptools' discovery methods
359
+ (for example by using `find_namespace_packages(...)`/`find_namespace:`
360
+ instead of `find_packages(...)`/`find:`).
361
+
362
+ You can read more about "package discovery" on setuptools documentation page:
363
+
364
+ - https://setuptools.pypa.io/en/latest/userguide/package_discovery.html
365
+
366
+ If you don't want {importable!r} to be distributed and are
367
+ already explicitly excluding {importable!r} via
368
+ `find_namespace_packages(...)/find_namespace` or `find_packages(...)/find`,
369
+ you can try to use `exclude_package_data`, or `include-package-data=False` in
370
+ combination with a more fine grained `package-data` configuration.
371
+
372
+ You can read more about "package data files" on setuptools documentation page:
373
+
374
+ - https://setuptools.pypa.io/en/latest/userguide/datafiles.html
375
+
376
+
377
+ [^1]: For Python, any directory (with suitable naming) can be imported,
378
+ even if it does not contain any `.py` files.
379
+ On the other hand, currently there is no concept of package data
380
+ directory, all directories are treated like packages.
381
+ """
382
+ # _DUE_DATE: still not defined as this is particularly controversial.
383
+ # Warning initially introduced in May 2022. See issue #3340 for discussion.
384
+
385
+ def __init__(self):
386
+ self._already_warned = set()
387
+
388
+ def is_module(self, file):
389
+ return file.endswith(".py") and file[: -len(".py")].isidentifier()
390
+
391
+ def importable_subpackage(self, parent, file):
392
+ pkg = Path(file).parent
393
+ parts = list(itertools.takewhile(str.isidentifier, pkg.parts))
394
+ if parts:
395
+ return ".".join([parent, *parts])
396
+ return None
397
+
398
+ def warn(self, importable):
399
+ if importable not in self._already_warned:
400
+ self._Warning.emit(importable=importable)
401
+ self._already_warned.add(importable)
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/develop.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from distutils.util import convert_path
2
+ from distutils import log
3
+ from distutils.errors import DistutilsOptionError
4
+ import os
5
+ import glob
6
+
7
+ from setuptools.command.easy_install import easy_install
8
+ from setuptools import _normalization
9
+ from setuptools import _path
10
+ from setuptools import namespaces
11
+ import setuptools
12
+
13
+ from ..unicode_utils import _read_utf8_with_fallback
14
+
15
+
16
+ class develop(namespaces.DevelopInstaller, easy_install):
17
+ """Set up package for development"""
18
+
19
+ description = "install package in 'development mode'"
20
+
21
+ user_options = easy_install.user_options + [
22
+ ("uninstall", "u", "Uninstall this source package"),
23
+ ("egg-path=", None, "Set the path to be used in the .egg-link file"),
24
+ ]
25
+
26
+ boolean_options = easy_install.boolean_options + ['uninstall']
27
+
28
+ command_consumes_arguments = False # override base
29
+
30
+ def run(self):
31
+ if self.uninstall:
32
+ self.multi_version = True
33
+ self.uninstall_link()
34
+ self.uninstall_namespaces()
35
+ else:
36
+ self.install_for_development()
37
+ self.warn_deprecated_options()
38
+
39
+ def initialize_options(self):
40
+ self.uninstall = None
41
+ self.egg_path = None
42
+ easy_install.initialize_options(self)
43
+ self.setup_path = None
44
+ self.always_copy_from = '.' # always copy eggs installed in curdir
45
+
46
+ def finalize_options(self):
47
+ import pkg_resources
48
+
49
+ ei = self.get_finalized_command("egg_info")
50
+ self.args = [ei.egg_name]
51
+
52
+ easy_install.finalize_options(self)
53
+ self.expand_basedirs()
54
+ self.expand_dirs()
55
+ # pick up setup-dir .egg files only: no .egg-info
56
+ self.package_index.scan(glob.glob('*.egg'))
57
+
58
+ egg_link_fn = (
59
+ _normalization.filename_component_broken(ei.egg_name) + '.egg-link'
60
+ )
61
+ self.egg_link = os.path.join(self.install_dir, egg_link_fn)
62
+ self.egg_base = ei.egg_base
63
+ if self.egg_path is None:
64
+ self.egg_path = os.path.abspath(ei.egg_base)
65
+
66
+ target = _path.normpath(self.egg_base)
67
+ egg_path = _path.normpath(os.path.join(self.install_dir, self.egg_path))
68
+ if egg_path != target:
69
+ raise DistutilsOptionError(
70
+ "--egg-path must be a relative path from the install"
71
+ " directory to " + target
72
+ )
73
+
74
+ # Make a distribution for the package's source
75
+ self.dist = pkg_resources.Distribution(
76
+ target,
77
+ pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)),
78
+ project_name=ei.egg_name,
79
+ )
80
+
81
+ self.setup_path = self._resolve_setup_path(
82
+ self.egg_base,
83
+ self.install_dir,
84
+ self.egg_path,
85
+ )
86
+
87
+ @staticmethod
88
+ def _resolve_setup_path(egg_base, install_dir, egg_path):
89
+ """
90
+ Generate a path from egg_base back to '.' where the
91
+ setup script resides and ensure that path points to the
92
+ setup path from $install_dir/$egg_path.
93
+ """
94
+ path_to_setup = egg_base.replace(os.sep, '/').rstrip('/')
95
+ if path_to_setup != os.curdir:
96
+ path_to_setup = '../' * (path_to_setup.count('/') + 1)
97
+ resolved = _path.normpath(os.path.join(install_dir, egg_path, path_to_setup))
98
+ curdir = _path.normpath(os.curdir)
99
+ if resolved != curdir:
100
+ raise DistutilsOptionError(
101
+ "Can't get a consistent path to setup script from"
102
+ " installation directory",
103
+ resolved,
104
+ curdir,
105
+ )
106
+ return path_to_setup
107
+
108
+ def install_for_development(self):
109
+ self.run_command('egg_info')
110
+
111
+ # Build extensions in-place
112
+ self.reinitialize_command('build_ext', inplace=True)
113
+ self.run_command('build_ext')
114
+
115
+ if setuptools.bootstrap_install_from:
116
+ self.easy_install(setuptools.bootstrap_install_from)
117
+ setuptools.bootstrap_install_from = None
118
+
119
+ self.install_namespaces()
120
+
121
+ # create an .egg-link in the installation dir, pointing to our egg
122
+ log.info("Creating %s (link to %s)", self.egg_link, self.egg_base)
123
+ if not self.dry_run:
124
+ with open(self.egg_link, "w", encoding="utf-8") as f:
125
+ f.write(self.egg_path + "\n" + self.setup_path)
126
+ # postprocess the installed distro, fixing up .pth, installing scripts,
127
+ # and handling requirements
128
+ self.process_distribution(None, self.dist, not self.no_deps)
129
+
130
+ def uninstall_link(self):
131
+ if os.path.exists(self.egg_link):
132
+ log.info("Removing %s (link to %s)", self.egg_link, self.egg_base)
133
+
134
+ contents = [
135
+ line.rstrip()
136
+ for line in _read_utf8_with_fallback(self.egg_link).splitlines()
137
+ ]
138
+
139
+ if contents not in ([self.egg_path], [self.egg_path, self.setup_path]):
140
+ log.warn("Link points to %s: uninstall aborted", contents)
141
+ return
142
+ if not self.dry_run:
143
+ os.unlink(self.egg_link)
144
+ if not self.dry_run:
145
+ self.update_pth(self.dist) # remove any .pth link to us
146
+ if self.distribution.scripts:
147
+ # XXX should also check for entry point scripts!
148
+ log.warn("Note: you must uninstall or replace scripts manually!")
149
+
150
+ def install_egg_scripts(self, dist):
151
+ if dist is not self.dist:
152
+ # Installing a dependency, so fall back to normal behavior
153
+ return easy_install.install_egg_scripts(self, dist)
154
+
155
+ # create wrapper scripts in the script dir, pointing to dist.scripts
156
+
157
+ # new-style...
158
+ self.install_wrapper_scripts(dist)
159
+
160
+ # ...and old-style
161
+ for script_name in self.distribution.scripts or []:
162
+ script_path = os.path.abspath(convert_path(script_name))
163
+ script_name = os.path.basename(script_path)
164
+ script_text = _read_utf8_with_fallback(script_path)
165
+ self.install_script(dist, script_name, script_text, script_path)
166
+
167
+ return None
168
+
169
+ def install_wrapper_scripts(self, dist):
170
+ dist = VersionlessRequirement(dist)
171
+ return easy_install.install_wrapper_scripts(self, dist)
172
+
173
+
174
+ class VersionlessRequirement:
175
+ """
176
+ Adapt a pkg_resources.Distribution to simply return the project
177
+ name as the 'requirement' so that scripts will work across
178
+ multiple versions.
179
+
180
+ >>> from pkg_resources import Distribution
181
+ >>> dist = Distribution(project_name='foo', version='1.0')
182
+ >>> str(dist.as_requirement())
183
+ 'foo==1.0'
184
+ >>> adapted_dist = VersionlessRequirement(dist)
185
+ >>> str(adapted_dist.as_requirement())
186
+ 'foo'
187
+ """
188
+
189
+ def __init__(self, dist):
190
+ self.__dist = dist
191
+
192
+ def __getattr__(self, name):
193
+ return getattr(self.__dist, name)
194
+
195
+ def as_requirement(self):
196
+ return self.project_name
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/dist_info.py ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Create a dist_info directory
3
+ As defined in the wheel specification
4
+ """
5
+
6
+ import os
7
+ import shutil
8
+ from contextlib import contextmanager
9
+ from distutils import log
10
+ from distutils.core import Command
11
+ from pathlib import Path
12
+ from typing import cast
13
+
14
+ from .. import _normalization
15
+ from .egg_info import egg_info as egg_info_cls
16
+
17
+
18
+ class dist_info(Command):
19
+ """
20
+ This command is private and reserved for internal use of setuptools,
21
+ users should rely on ``setuptools.build_meta`` APIs.
22
+ """
23
+
24
+ description = "DO NOT CALL DIRECTLY, INTERNAL ONLY: create .dist-info directory"
25
+
26
+ user_options = [
27
+ (
28
+ 'output-dir=',
29
+ 'o',
30
+ "directory inside of which the .dist-info will be"
31
+ "created [default: top of the source tree]",
32
+ ),
33
+ ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
34
+ ('tag-build=', 'b', "Specify explicit tag to add to version number"),
35
+ ('no-date', 'D', "Don't include date stamp [default]"),
36
+ ('keep-egg-info', None, "*TRANSITIONAL* will be removed in the future"),
37
+ ]
38
+
39
+ boolean_options = ['tag-date', 'keep-egg-info']
40
+ negative_opt = {'no-date': 'tag-date'}
41
+
42
+ def initialize_options(self):
43
+ self.output_dir = None
44
+ self.name = None
45
+ self.dist_info_dir = None
46
+ self.tag_date = None
47
+ self.tag_build = None
48
+ self.keep_egg_info = False
49
+
50
+ def finalize_options(self):
51
+ dist = self.distribution
52
+ project_dir = dist.src_root or os.curdir
53
+ self.output_dir = Path(self.output_dir or project_dir)
54
+
55
+ egg_info = cast(egg_info_cls, self.reinitialize_command("egg_info"))
56
+ egg_info.egg_base = str(self.output_dir)
57
+
58
+ if self.tag_date:
59
+ egg_info.tag_date = self.tag_date
60
+ else:
61
+ self.tag_date = egg_info.tag_date
62
+
63
+ if self.tag_build:
64
+ egg_info.tag_build = self.tag_build
65
+ else:
66
+ self.tag_build = egg_info.tag_build
67
+
68
+ egg_info.finalize_options()
69
+ self.egg_info = egg_info
70
+
71
+ name = _normalization.safer_name(dist.get_name())
72
+ version = _normalization.safer_best_effort_version(dist.get_version())
73
+ self.name = f"{name}-{version}"
74
+ self.dist_info_dir = os.path.join(self.output_dir, f"{self.name}.dist-info")
75
+
76
+ @contextmanager
77
+ def _maybe_bkp_dir(self, dir_path: str, requires_bkp: bool):
78
+ if requires_bkp:
79
+ bkp_name = f"{dir_path}.__bkp__"
80
+ _rm(bkp_name, ignore_errors=True)
81
+ shutil.copytree(dir_path, bkp_name, dirs_exist_ok=True, symlinks=True)
82
+ try:
83
+ yield
84
+ finally:
85
+ _rm(dir_path, ignore_errors=True)
86
+ shutil.move(bkp_name, dir_path)
87
+ else:
88
+ yield
89
+
90
+ def run(self):
91
+ self.output_dir.mkdir(parents=True, exist_ok=True)
92
+ self.egg_info.run()
93
+ egg_info_dir = self.egg_info.egg_info
94
+ assert os.path.isdir(egg_info_dir), ".egg-info dir should have been created"
95
+
96
+ log.info("creating '{}'".format(os.path.abspath(self.dist_info_dir)))
97
+ bdist_wheel = self.get_finalized_command('bdist_wheel')
98
+
99
+ # TODO: if bdist_wheel if merged into setuptools, just add "keep_egg_info" there
100
+ with self._maybe_bkp_dir(egg_info_dir, self.keep_egg_info):
101
+ bdist_wheel.egg2dist(egg_info_dir, self.dist_info_dir)
102
+
103
+
104
+ def _rm(dir_name, **opts):
105
+ if os.path.isdir(dir_name):
106
+ shutil.rmtree(dir_name, **opts)
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/editable_wheel.py ADDED
@@ -0,0 +1,918 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Create a wheel that, when installed, will make the source package 'editable'
3
+ (add it to the interpreter's path, including metadata) per PEP 660. Replaces
4
+ 'setup.py develop'.
5
+
6
+ .. note::
7
+ One of the mechanisms briefly mentioned in PEP 660 to implement editable installs is
8
+ to create a separated directory inside ``build`` and use a .pth file to point to that
9
+ directory. In the context of this file such directory is referred as
10
+ *auxiliary build directory* or ``auxiliary_dir``.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import logging
16
+ import io
17
+ import os
18
+ import shutil
19
+ import traceback
20
+ from contextlib import suppress
21
+ from enum import Enum
22
+ from inspect import cleandoc
23
+ from itertools import chain, starmap
24
+ from pathlib import Path
25
+ from tempfile import TemporaryDirectory
26
+ from typing import (
27
+ TYPE_CHECKING,
28
+ Iterable,
29
+ Iterator,
30
+ Mapping,
31
+ Protocol,
32
+ TypeVar,
33
+ cast,
34
+ )
35
+
36
+ from .. import (
37
+ Command,
38
+ _normalization,
39
+ _path,
40
+ errors,
41
+ namespaces,
42
+ )
43
+ from .._path import StrPath
44
+ from ..compat import py39
45
+ from ..discovery import find_package_path
46
+ from ..dist import Distribution
47
+ from ..warnings import (
48
+ InformationOnly,
49
+ SetuptoolsDeprecationWarning,
50
+ SetuptoolsWarning,
51
+ )
52
+ from .build import build as build_cls
53
+ from .build_py import build_py as build_py_cls
54
+ from .dist_info import dist_info as dist_info_cls
55
+ from .egg_info import egg_info as egg_info_cls
56
+ from .install import install as install_cls
57
+ from .install_scripts import install_scripts as install_scripts_cls
58
+
59
+ if TYPE_CHECKING:
60
+ from .._vendor.wheel.wheelfile import WheelFile
61
+
62
+ _P = TypeVar("_P", bound=StrPath)
63
+ _logger = logging.getLogger(__name__)
64
+
65
+
66
+ class _EditableMode(Enum):
67
+ """
68
+ Possible editable installation modes:
69
+ `lenient` (new files automatically added to the package - DEFAULT);
70
+ `strict` (requires a new installation when files are added/removed); or
71
+ `compat` (attempts to emulate `python setup.py develop` - DEPRECATED).
72
+ """
73
+
74
+ STRICT = "strict"
75
+ LENIENT = "lenient"
76
+ COMPAT = "compat" # TODO: Remove `compat` after Dec/2022.
77
+
78
+ @classmethod
79
+ def convert(cls, mode: str | None) -> _EditableMode:
80
+ if not mode:
81
+ return _EditableMode.LENIENT # default
82
+
83
+ _mode = mode.upper()
84
+ if _mode not in _EditableMode.__members__:
85
+ raise errors.OptionError(f"Invalid editable mode: {mode!r}. Try: 'strict'.")
86
+
87
+ if _mode == "COMPAT":
88
+ SetuptoolsDeprecationWarning.emit(
89
+ "Compat editable installs",
90
+ """
91
+ The 'compat' editable mode is transitional and will be removed
92
+ in future versions of `setuptools`.
93
+ Please adapt your code accordingly to use either the 'strict' or the
94
+ 'lenient' modes.
95
+ """,
96
+ see_docs="userguide/development_mode.html",
97
+ # TODO: define due_date
98
+ # There is a series of shortcomings with the available editable install
99
+ # methods, and they are very controversial. This is something that still
100
+ # needs work.
101
+ # Moreover, `pip` is still hiding this warning, so users are not aware.
102
+ )
103
+
104
+ return _EditableMode[_mode]
105
+
106
+
107
+ _STRICT_WARNING = """
108
+ New or renamed files may not be automatically picked up without a new installation.
109
+ """
110
+
111
+ _LENIENT_WARNING = """
112
+ Options like `package-data`, `include/exclude-package-data` or
113
+ `packages.find.exclude/include` may have no effect.
114
+ """
115
+
116
+
117
+ class editable_wheel(Command):
118
+ """Build 'editable' wheel for development.
119
+ This command is private and reserved for internal use of setuptools,
120
+ users should rely on ``setuptools.build_meta`` APIs.
121
+ """
122
+
123
+ description = "DO NOT CALL DIRECTLY, INTERNAL ONLY: create PEP 660 editable wheel"
124
+
125
+ user_options = [
126
+ ("dist-dir=", "d", "directory to put final built distributions in"),
127
+ ("dist-info-dir=", "I", "path to a pre-build .dist-info directory"),
128
+ ("mode=", None, cleandoc(_EditableMode.__doc__ or "")),
129
+ ]
130
+
131
+ def initialize_options(self):
132
+ self.dist_dir = None
133
+ self.dist_info_dir = None
134
+ self.project_dir = None
135
+ self.mode = None
136
+
137
+ def finalize_options(self):
138
+ dist = self.distribution
139
+ self.project_dir = dist.src_root or os.curdir
140
+ self.package_dir = dist.package_dir or {}
141
+ self.dist_dir = Path(self.dist_dir or os.path.join(self.project_dir, "dist"))
142
+
143
+ def run(self):
144
+ try:
145
+ self.dist_dir.mkdir(exist_ok=True)
146
+ self._ensure_dist_info()
147
+
148
+ # Add missing dist_info files
149
+ self.reinitialize_command("bdist_wheel")
150
+ bdist_wheel = self.get_finalized_command("bdist_wheel")
151
+ bdist_wheel.write_wheelfile(self.dist_info_dir)
152
+
153
+ self._create_wheel_file(bdist_wheel)
154
+ except Exception:
155
+ traceback.print_exc()
156
+ project = self.distribution.name or self.distribution.get_name()
157
+ _DebuggingTips.emit(project=project)
158
+ raise
159
+
160
+ def _ensure_dist_info(self):
161
+ if self.dist_info_dir is None:
162
+ dist_info = cast(dist_info_cls, self.reinitialize_command("dist_info"))
163
+ dist_info.output_dir = self.dist_dir
164
+ dist_info.ensure_finalized()
165
+ dist_info.run()
166
+ self.dist_info_dir = dist_info.dist_info_dir
167
+ else:
168
+ assert str(self.dist_info_dir).endswith(".dist-info")
169
+ assert Path(self.dist_info_dir, "METADATA").exists()
170
+
171
+ def _install_namespaces(self, installation_dir, pth_prefix):
172
+ # XXX: Only required to support the deprecated namespace practice
173
+ dist = self.distribution
174
+ if not dist.namespace_packages:
175
+ return
176
+
177
+ src_root = Path(self.project_dir, self.package_dir.get("", ".")).resolve()
178
+ installer = _NamespaceInstaller(dist, installation_dir, pth_prefix, src_root)
179
+ installer.install_namespaces()
180
+
181
+ def _find_egg_info_dir(self) -> str | None:
182
+ parent_dir = Path(self.dist_info_dir).parent if self.dist_info_dir else Path()
183
+ candidates = map(str, parent_dir.glob("*.egg-info"))
184
+ return next(candidates, None)
185
+
186
+ def _configure_build(
187
+ self, name: str, unpacked_wheel: StrPath, build_lib: StrPath, tmp_dir: StrPath
188
+ ):
189
+ """Configure commands to behave in the following ways:
190
+
191
+ - Build commands can write to ``build_lib`` if they really want to...
192
+ (but this folder is expected to be ignored and modules are expected to live
193
+ in the project directory...)
194
+ - Binary extensions should be built in-place (editable_mode = True)
195
+ - Data/header/script files are not part of the "editable" specification
196
+ so they are written directly to the unpacked_wheel directory.
197
+ """
198
+ # Non-editable files (data, headers, scripts) are written directly to the
199
+ # unpacked_wheel
200
+
201
+ dist = self.distribution
202
+ wheel = str(unpacked_wheel)
203
+ build_lib = str(build_lib)
204
+ data = str(Path(unpacked_wheel, f"{name}.data", "data"))
205
+ headers = str(Path(unpacked_wheel, f"{name}.data", "headers"))
206
+ scripts = str(Path(unpacked_wheel, f"{name}.data", "scripts"))
207
+
208
+ # egg-info may be generated again to create a manifest (used for package data)
209
+ egg_info = cast(
210
+ egg_info_cls, dist.reinitialize_command("egg_info", reinit_subcommands=True)
211
+ )
212
+ egg_info.egg_base = str(tmp_dir)
213
+ egg_info.ignore_egg_info_in_manifest = True
214
+
215
+ build = cast(
216
+ build_cls, dist.reinitialize_command("build", reinit_subcommands=True)
217
+ )
218
+ install = cast(
219
+ install_cls, dist.reinitialize_command("install", reinit_subcommands=True)
220
+ )
221
+
222
+ build.build_platlib = build.build_purelib = build.build_lib = build_lib
223
+ install.install_purelib = install.install_platlib = install.install_lib = wheel
224
+ install.install_scripts = build.build_scripts = scripts
225
+ install.install_headers = headers
226
+ install.install_data = data
227
+
228
+ install_scripts = cast(
229
+ install_scripts_cls, dist.get_command_obj("install_scripts")
230
+ )
231
+ install_scripts.no_ep = True
232
+
233
+ build.build_temp = str(tmp_dir)
234
+
235
+ build_py = cast(build_py_cls, dist.get_command_obj("build_py"))
236
+ build_py.compile = False
237
+ build_py.existing_egg_info_dir = self._find_egg_info_dir()
238
+
239
+ self._set_editable_mode()
240
+
241
+ build.ensure_finalized()
242
+ install.ensure_finalized()
243
+
244
+ def _set_editable_mode(self):
245
+ """Set the ``editable_mode`` flag in the build sub-commands"""
246
+ dist = self.distribution
247
+ build = dist.get_command_obj("build")
248
+ # TODO: Update typeshed distutils stubs to overload non-None return type by default
249
+ for cmd_name in build.get_sub_commands():
250
+ cmd = dist.get_command_obj(cmd_name)
251
+ if hasattr(cmd, "editable_mode"):
252
+ cmd.editable_mode = True
253
+ elif hasattr(cmd, "inplace"):
254
+ cmd.inplace = True # backward compatibility with distutils
255
+
256
+ def _collect_build_outputs(self) -> tuple[list[str], dict[str, str]]:
257
+ files: list[str] = []
258
+ mapping: dict[str, str] = {}
259
+ build = self.get_finalized_command("build")
260
+
261
+ for cmd_name in build.get_sub_commands():
262
+ cmd = self.get_finalized_command(cmd_name)
263
+ if hasattr(cmd, "get_outputs"):
264
+ files.extend(cmd.get_outputs() or [])
265
+ if hasattr(cmd, "get_output_mapping"):
266
+ mapping.update(cmd.get_output_mapping() or {})
267
+
268
+ return files, mapping
269
+
270
+ def _run_build_commands(
271
+ self,
272
+ dist_name: str,
273
+ unpacked_wheel: StrPath,
274
+ build_lib: StrPath,
275
+ tmp_dir: StrPath,
276
+ ) -> tuple[list[str], dict[str, str]]:
277
+ self._configure_build(dist_name, unpacked_wheel, build_lib, tmp_dir)
278
+ self._run_build_subcommands()
279
+ files, mapping = self._collect_build_outputs()
280
+ self._run_install("headers")
281
+ self._run_install("scripts")
282
+ self._run_install("data")
283
+ return files, mapping
284
+
285
+ def _run_build_subcommands(self) -> None:
286
+ """
287
+ Issue #3501 indicates that some plugins/customizations might rely on:
288
+
289
+ 1. ``build_py`` not running
290
+ 2. ``build_py`` always copying files to ``build_lib``
291
+
292
+ However both these assumptions may be false in editable_wheel.
293
+ This method implements a temporary workaround to support the ecosystem
294
+ while the implementations catch up.
295
+ """
296
+ # TODO: Once plugins/customisations had the chance to catch up, replace
297
+ # `self._run_build_subcommands()` with `self.run_command("build")`.
298
+ # Also remove _safely_run, TestCustomBuildPy. Suggested date: Aug/2023.
299
+ build = self.get_finalized_command("build")
300
+ for name in build.get_sub_commands():
301
+ cmd = self.get_finalized_command(name)
302
+ if name == "build_py" and type(cmd) != build_py_cls:
303
+ self._safely_run(name)
304
+ else:
305
+ self.run_command(name)
306
+
307
+ def _safely_run(self, cmd_name: str):
308
+ try:
309
+ return self.run_command(cmd_name)
310
+ except Exception:
311
+ SetuptoolsDeprecationWarning.emit(
312
+ "Customization incompatible with editable install",
313
+ f"""
314
+ {traceback.format_exc()}
315
+
316
+ If you are seeing this warning it is very likely that a setuptools
317
+ plugin or customization overrides the `{cmd_name}` command, without
318
+ taking into consideration how editable installs run build steps
319
+ starting from setuptools v64.0.0.
320
+
321
+ Plugin authors and developers relying on custom build steps are
322
+ encouraged to update their `{cmd_name}` implementation considering the
323
+ information about editable installs in
324
+ https://setuptools.pypa.io/en/latest/userguide/extension.html.
325
+
326
+ For the time being `setuptools` will silence this error and ignore
327
+ the faulty command, but this behaviour will change in future versions.
328
+ """,
329
+ # TODO: define due_date
330
+ # There is a series of shortcomings with the available editable install
331
+ # methods, and they are very controversial. This is something that still
332
+ # needs work.
333
+ )
334
+
335
+ def _create_wheel_file(self, bdist_wheel):
336
+ from ..extern.wheel.wheelfile import WheelFile
337
+
338
+ dist_info = self.get_finalized_command("dist_info")
339
+ dist_name = dist_info.name
340
+ tag = "-".join(bdist_wheel.get_tag())
341
+ build_tag = "0.editable" # According to PEP 427 needs to start with digit
342
+ archive_name = f"{dist_name}-{build_tag}-{tag}.whl"
343
+ wheel_path = Path(self.dist_dir, archive_name)
344
+ if wheel_path.exists():
345
+ wheel_path.unlink()
346
+
347
+ unpacked_wheel = TemporaryDirectory(suffix=archive_name)
348
+ build_lib = TemporaryDirectory(suffix=".build-lib")
349
+ build_tmp = TemporaryDirectory(suffix=".build-temp")
350
+
351
+ with unpacked_wheel as unpacked, build_lib as lib, build_tmp as tmp:
352
+ unpacked_dist_info = Path(unpacked, Path(self.dist_info_dir).name)
353
+ shutil.copytree(self.dist_info_dir, unpacked_dist_info)
354
+ self._install_namespaces(unpacked, dist_name)
355
+ files, mapping = self._run_build_commands(dist_name, unpacked, lib, tmp)
356
+ strategy = self._select_strategy(dist_name, tag, lib)
357
+ with strategy, WheelFile(wheel_path, "w") as wheel_obj:
358
+ strategy(wheel_obj, files, mapping)
359
+ wheel_obj.write_files(unpacked)
360
+
361
+ return wheel_path
362
+
363
+ def _run_install(self, category: str):
364
+ has_category = getattr(self.distribution, f"has_{category}", None)
365
+ if has_category and has_category():
366
+ _logger.info(f"Installing {category} as non editable")
367
+ self.run_command(f"install_{category}")
368
+
369
+ def _select_strategy(
370
+ self,
371
+ name: str,
372
+ tag: str,
373
+ build_lib: StrPath,
374
+ ) -> EditableStrategy:
375
+ """Decides which strategy to use to implement an editable installation."""
376
+ build_name = f"__editable__.{name}-{tag}"
377
+ project_dir = Path(self.project_dir)
378
+ mode = _EditableMode.convert(self.mode)
379
+
380
+ if mode is _EditableMode.STRICT:
381
+ auxiliary_dir = _empty_dir(Path(self.project_dir, "build", build_name))
382
+ return _LinkTree(self.distribution, name, auxiliary_dir, build_lib)
383
+
384
+ packages = _find_packages(self.distribution)
385
+ has_simple_layout = _simple_layout(packages, self.package_dir, project_dir)
386
+ is_compat_mode = mode is _EditableMode.COMPAT
387
+ if set(self.package_dir) == {""} and has_simple_layout or is_compat_mode:
388
+ # src-layout(ish) is relatively safe for a simple pth file
389
+ src_dir = self.package_dir.get("", ".")
390
+ return _StaticPth(self.distribution, name, [Path(project_dir, src_dir)])
391
+
392
+ # Use a MetaPathFinder to avoid adding accidental top-level packages/modules
393
+ return _TopLevelFinder(self.distribution, name)
394
+
395
+
396
+ class EditableStrategy(Protocol):
397
+ def __call__(self, wheel: WheelFile, files: list[str], mapping: dict[str, str]): ...
398
+
399
+ def __enter__(self): ...
400
+
401
+ def __exit__(self, _exc_type, _exc_value, _traceback): ...
402
+
403
+
404
+ class _StaticPth:
405
+ def __init__(self, dist: Distribution, name: str, path_entries: list[Path]):
406
+ self.dist = dist
407
+ self.name = name
408
+ self.path_entries = path_entries
409
+
410
+ def __call__(self, wheel: WheelFile, files: list[str], mapping: dict[str, str]):
411
+ entries = "\n".join(str(p.resolve()) for p in self.path_entries)
412
+ contents = _encode_pth(f"{entries}\n")
413
+ wheel.writestr(f"__editable__.{self.name}.pth", contents)
414
+
415
+ def __enter__(self):
416
+ msg = f"""
417
+ Editable install will be performed using .pth file to extend `sys.path` with:
418
+ {list(map(os.fspath, self.path_entries))!r}
419
+ """
420
+ _logger.warning(msg + _LENIENT_WARNING)
421
+ return self
422
+
423
+ def __exit__(self, _exc_type, _exc_value, _traceback): ...
424
+
425
+
426
+ class _LinkTree(_StaticPth):
427
+ """
428
+ Creates a ``.pth`` file that points to a link tree in the ``auxiliary_dir``.
429
+
430
+ This strategy will only link files (not dirs), so it can be implemented in
431
+ any OS, even if that means using hardlinks instead of symlinks.
432
+
433
+ By collocating ``auxiliary_dir`` and the original source code, limitations
434
+ with hardlinks should be avoided.
435
+ """
436
+
437
+ def __init__(
438
+ self,
439
+ dist: Distribution,
440
+ name: str,
441
+ auxiliary_dir: StrPath,
442
+ build_lib: StrPath,
443
+ ):
444
+ self.auxiliary_dir = Path(auxiliary_dir)
445
+ self.build_lib = Path(build_lib).resolve()
446
+ # TODO: Update typeshed distutils stubs to overload non-None return type by default
447
+ self._file = dist.get_command_obj("build_py").copy_file # type: ignore[union-attr]
448
+ super().__init__(dist, name, [self.auxiliary_dir])
449
+
450
+ def __call__(self, wheel: WheelFile, files: list[str], mapping: dict[str, str]):
451
+ self._create_links(files, mapping)
452
+ super().__call__(wheel, files, mapping)
453
+
454
+ def _normalize_output(self, file: str) -> str | None:
455
+ # Files relative to build_lib will be normalized to None
456
+ with suppress(ValueError):
457
+ path = Path(file).resolve().relative_to(self.build_lib)
458
+ return str(path).replace(os.sep, '/')
459
+ return None
460
+
461
+ def _create_file(self, relative_output: str, src_file: str, link=None):
462
+ dest = self.auxiliary_dir / relative_output
463
+ if not dest.parent.is_dir():
464
+ dest.parent.mkdir(parents=True)
465
+ # TODO: Update typeshed distutils stubs so distutils.cmd.Command.copy_file, accepts PathLike
466
+ # same with methods used by copy_file
467
+ self._file(src_file, dest, link=link) # type: ignore[arg-type]
468
+
469
+ def _create_links(self, outputs, output_mapping):
470
+ self.auxiliary_dir.mkdir(parents=True, exist_ok=True)
471
+ link_type = "sym" if _can_symlink_files(self.auxiliary_dir) else "hard"
472
+ mappings = {self._normalize_output(k): v for k, v in output_mapping.items()}
473
+ mappings.pop(None, None) # remove files that are not relative to build_lib
474
+
475
+ for output in outputs:
476
+ relative = self._normalize_output(output)
477
+ if relative and relative not in mappings:
478
+ self._create_file(relative, output)
479
+
480
+ for relative, src in mappings.items():
481
+ self._create_file(relative, src, link=link_type)
482
+
483
+ def __enter__(self):
484
+ msg = "Strict editable install will be performed using a link tree.\n"
485
+ _logger.warning(msg + _STRICT_WARNING)
486
+ return self
487
+
488
+ def __exit__(self, _exc_type, _exc_value, _traceback):
489
+ msg = f"""\n
490
+ Strict editable installation performed using the auxiliary directory:
491
+ {self.auxiliary_dir}
492
+
493
+ Please be careful to not remove this directory, otherwise you might not be able
494
+ to import/use your package.
495
+ """
496
+ InformationOnly.emit("Editable installation.", msg)
497
+
498
+
499
+ class _TopLevelFinder:
500
+ def __init__(self, dist: Distribution, name: str):
501
+ self.dist = dist
502
+ self.name = name
503
+
504
+ def template_vars(self) -> tuple[str, str, dict[str, str], dict[str, list[str]]]:
505
+ src_root = self.dist.src_root or os.curdir
506
+ top_level = chain(_find_packages(self.dist), _find_top_level_modules(self.dist))
507
+ package_dir = self.dist.package_dir or {}
508
+ roots = _find_package_roots(top_level, package_dir, src_root)
509
+
510
+ namespaces_: dict[str, list[str]] = dict(
511
+ chain(
512
+ _find_namespaces(self.dist.packages or [], roots),
513
+ ((ns, []) for ns in _find_virtual_namespaces(roots)),
514
+ )
515
+ )
516
+
517
+ legacy_namespaces = {
518
+ pkg: find_package_path(pkg, roots, self.dist.src_root or "")
519
+ for pkg in self.dist.namespace_packages or []
520
+ }
521
+
522
+ mapping = {**roots, **legacy_namespaces}
523
+ # ^-- We need to explicitly add the legacy_namespaces to the mapping to be
524
+ # able to import their modules even if another package sharing the same
525
+ # namespace is installed in a conventional (non-editable) way.
526
+
527
+ name = f"__editable__.{self.name}.finder"
528
+ finder = _normalization.safe_identifier(name)
529
+ return finder, name, mapping, namespaces_
530
+
531
+ def get_implementation(self) -> Iterator[tuple[str, bytes]]:
532
+ finder, name, mapping, namespaces_ = self.template_vars()
533
+
534
+ content = bytes(_finder_template(name, mapping, namespaces_), "utf-8")
535
+ yield (f"{finder}.py", content)
536
+
537
+ content = _encode_pth(f"import {finder}; {finder}.install()")
538
+ yield (f"__editable__.{self.name}.pth", content)
539
+
540
+ def __call__(self, wheel: WheelFile, files: list[str], mapping: dict[str, str]):
541
+ for file, content in self.get_implementation():
542
+ wheel.writestr(file, content)
543
+
544
+ def __enter__(self):
545
+ msg = "Editable install will be performed using a meta path finder.\n"
546
+ _logger.warning(msg + _LENIENT_WARNING)
547
+ return self
548
+
549
+ def __exit__(self, _exc_type, _exc_value, _traceback):
550
+ msg = """\n
551
+ Please be careful with folders in your working directory with the same
552
+ name as your package as they may take precedence during imports.
553
+ """
554
+ InformationOnly.emit("Editable installation.", msg)
555
+
556
+
557
+ def _encode_pth(content: str) -> bytes:
558
+ """.pth files are always read with 'locale' encoding, the recommendation
559
+ from the cpython core developers is to write them as ``open(path, "w")``
560
+ and ignore warnings (see python/cpython#77102, pypa/setuptools#3937).
561
+ This function tries to simulate this behaviour without having to create an
562
+ actual file, in a way that supports a range of active Python versions.
563
+ (There seems to be some variety in the way different version of Python handle
564
+ ``encoding=None``, not all of them use ``locale.getpreferredencoding(False)``
565
+ or ``locale.getencoding()``).
566
+ """
567
+ with io.BytesIO() as buffer:
568
+ wrapper = io.TextIOWrapper(buffer, encoding=py39.LOCALE_ENCODING)
569
+ wrapper.write(content)
570
+ wrapper.flush()
571
+ buffer.seek(0)
572
+ return buffer.read()
573
+
574
+
575
+ def _can_symlink_files(base_dir: Path) -> bool:
576
+ with TemporaryDirectory(dir=str(base_dir.resolve())) as tmp:
577
+ path1, path2 = Path(tmp, "file1.txt"), Path(tmp, "file2.txt")
578
+ path1.write_text("file1", encoding="utf-8")
579
+ with suppress(AttributeError, NotImplementedError, OSError):
580
+ os.symlink(path1, path2)
581
+ if path2.is_symlink() and path2.read_text(encoding="utf-8") == "file1":
582
+ return True
583
+
584
+ try:
585
+ os.link(path1, path2) # Ensure hard links can be created
586
+ except Exception as ex:
587
+ msg = (
588
+ "File system does not seem to support either symlinks or hard links. "
589
+ "Strict editable installs require one of them to be supported."
590
+ )
591
+ raise LinksNotSupported(msg) from ex
592
+ return False
593
+
594
+
595
+ def _simple_layout(
596
+ packages: Iterable[str], package_dir: dict[str, str], project_dir: StrPath
597
+ ) -> bool:
598
+ """Return ``True`` if:
599
+ - all packages are contained by the same parent directory, **and**
600
+ - all packages become importable if the parent directory is added to ``sys.path``.
601
+
602
+ >>> _simple_layout(['a'], {"": "src"}, "/tmp/myproj")
603
+ True
604
+ >>> _simple_layout(['a', 'a.b'], {"": "src"}, "/tmp/myproj")
605
+ True
606
+ >>> _simple_layout(['a', 'a.b'], {}, "/tmp/myproj")
607
+ True
608
+ >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"": "src"}, "/tmp/myproj")
609
+ True
610
+ >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "a", "b": "b"}, ".")
611
+ True
612
+ >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a", "b": "_b"}, ".")
613
+ False
614
+ >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a": "_a"}, "/tmp/myproj")
615
+ False
616
+ >>> _simple_layout(['a', 'a.a1', 'a.a1.a2', 'b'], {"a.a1.a2": "_a2"}, ".")
617
+ False
618
+ >>> _simple_layout(['a', 'a.b'], {"": "src", "a.b": "_ab"}, "/tmp/myproj")
619
+ False
620
+ >>> # Special cases, no packages yet:
621
+ >>> _simple_layout([], {"": "src"}, "/tmp/myproj")
622
+ True
623
+ >>> _simple_layout([], {"a": "_a", "": "src"}, "/tmp/myproj")
624
+ False
625
+ """
626
+ layout = {pkg: find_package_path(pkg, package_dir, project_dir) for pkg in packages}
627
+ if not layout:
628
+ return set(package_dir) in ({}, {""})
629
+ parent = os.path.commonpath(starmap(_parent_path, layout.items()))
630
+ return all(
631
+ _path.same_path(Path(parent, *key.split('.')), value)
632
+ for key, value in layout.items()
633
+ )
634
+
635
+
636
+ def _parent_path(pkg, pkg_path):
637
+ """Infer the parent path containing a package, that if added to ``sys.path`` would
638
+ allow importing that package.
639
+ When ``pkg`` is directly mapped into a directory with a different name, return its
640
+ own path.
641
+ >>> _parent_path("a", "src/a")
642
+ 'src'
643
+ >>> _parent_path("b", "src/c")
644
+ 'src/c'
645
+ """
646
+ parent = pkg_path[: -len(pkg)] if pkg_path.endswith(pkg) else pkg_path
647
+ return parent.rstrip("/" + os.sep)
648
+
649
+
650
+ def _find_packages(dist: Distribution) -> Iterator[str]:
651
+ yield from iter(dist.packages or [])
652
+
653
+ py_modules = dist.py_modules or []
654
+ nested_modules = [mod for mod in py_modules if "." in mod]
655
+ if dist.ext_package:
656
+ yield dist.ext_package
657
+ else:
658
+ ext_modules = dist.ext_modules or []
659
+ nested_modules += [x.name for x in ext_modules if "." in x.name]
660
+
661
+ for module in nested_modules:
662
+ package, _, _ = module.rpartition(".")
663
+ yield package
664
+
665
+
666
+ def _find_top_level_modules(dist: Distribution) -> Iterator[str]:
667
+ py_modules = dist.py_modules or []
668
+ yield from (mod for mod in py_modules if "." not in mod)
669
+
670
+ if not dist.ext_package:
671
+ ext_modules = dist.ext_modules or []
672
+ yield from (x.name for x in ext_modules if "." not in x.name)
673
+
674
+
675
+ def _find_package_roots(
676
+ packages: Iterable[str],
677
+ package_dir: Mapping[str, str],
678
+ src_root: StrPath,
679
+ ) -> dict[str, str]:
680
+ pkg_roots: dict[str, str] = {
681
+ pkg: _absolute_root(find_package_path(pkg, package_dir, src_root))
682
+ for pkg in sorted(packages)
683
+ }
684
+
685
+ return _remove_nested(pkg_roots)
686
+
687
+
688
+ def _absolute_root(path: StrPath) -> str:
689
+ """Works for packages and top-level modules"""
690
+ path_ = Path(path)
691
+ parent = path_.parent
692
+
693
+ if path_.exists():
694
+ return str(path_.resolve())
695
+ else:
696
+ return str(parent.resolve() / path_.name)
697
+
698
+
699
+ def _find_virtual_namespaces(pkg_roots: dict[str, str]) -> Iterator[str]:
700
+ """By carefully designing ``package_dir``, it is possible to implement the logical
701
+ structure of PEP 420 in a package without the corresponding directories.
702
+
703
+ Moreover a parent package can be purposefully/accidentally skipped in the discovery
704
+ phase (e.g. ``find_packages(include=["mypkg.*"])``, when ``mypkg.foo`` is included
705
+ by ``mypkg`` itself is not).
706
+ We consider this case to also be a virtual namespace (ignoring the original
707
+ directory) to emulate a non-editable installation.
708
+
709
+ This function will try to find these kinds of namespaces.
710
+ """
711
+ for pkg in pkg_roots:
712
+ if "." not in pkg:
713
+ continue
714
+ parts = pkg.split(".")
715
+ for i in range(len(parts) - 1, 0, -1):
716
+ partial_name = ".".join(parts[:i])
717
+ path = Path(find_package_path(partial_name, pkg_roots, ""))
718
+ if not path.exists() or partial_name not in pkg_roots:
719
+ # partial_name not in pkg_roots ==> purposefully/accidentally skipped
720
+ yield partial_name
721
+
722
+
723
+ def _find_namespaces(
724
+ packages: list[str], pkg_roots: dict[str, str]
725
+ ) -> Iterator[tuple[str, list[str]]]:
726
+ for pkg in packages:
727
+ path = find_package_path(pkg, pkg_roots, "")
728
+ if Path(path).exists() and not Path(path, "__init__.py").exists():
729
+ yield (pkg, [path])
730
+
731
+
732
+ def _remove_nested(pkg_roots: dict[str, str]) -> dict[str, str]:
733
+ output = dict(pkg_roots.copy())
734
+
735
+ for pkg, path in reversed(list(pkg_roots.items())):
736
+ if any(
737
+ pkg != other and _is_nested(pkg, path, other, other_path)
738
+ for other, other_path in pkg_roots.items()
739
+ ):
740
+ output.pop(pkg)
741
+
742
+ return output
743
+
744
+
745
+ def _is_nested(pkg: str, pkg_path: str, parent: str, parent_path: str) -> bool:
746
+ """
747
+ Return ``True`` if ``pkg`` is nested inside ``parent`` both logically and in the
748
+ file system.
749
+ >>> _is_nested("a.b", "path/a/b", "a", "path/a")
750
+ True
751
+ >>> _is_nested("a.b", "path/a/b", "a", "otherpath/a")
752
+ False
753
+ >>> _is_nested("a.b", "path/a/b", "c", "path/c")
754
+ False
755
+ >>> _is_nested("a.a", "path/a/a", "a", "path/a")
756
+ True
757
+ >>> _is_nested("b.a", "path/b/a", "a", "path/a")
758
+ False
759
+ """
760
+ norm_pkg_path = _path.normpath(pkg_path)
761
+ rest = pkg.replace(parent, "", 1).strip(".").split(".")
762
+ return pkg.startswith(parent) and norm_pkg_path == _path.normpath(
763
+ Path(parent_path, *rest)
764
+ )
765
+
766
+
767
+ def _empty_dir(dir_: _P) -> _P:
768
+ """Create a directory ensured to be empty. Existing files may be removed."""
769
+ shutil.rmtree(dir_, ignore_errors=True)
770
+ os.makedirs(dir_)
771
+ return dir_
772
+
773
+
774
+ class _NamespaceInstaller(namespaces.Installer):
775
+ def __init__(self, distribution, installation_dir, editable_name, src_root):
776
+ self.distribution = distribution
777
+ self.src_root = src_root
778
+ self.installation_dir = installation_dir
779
+ self.editable_name = editable_name
780
+ self.outputs = []
781
+ self.dry_run = False
782
+
783
+ def _get_nspkg_file(self):
784
+ """Installation target."""
785
+ return os.path.join(self.installation_dir, self.editable_name + self.nspkg_ext)
786
+
787
+ def _get_root(self):
788
+ """Where the modules/packages should be loaded from."""
789
+ return repr(str(self.src_root))
790
+
791
+
792
+ _FINDER_TEMPLATE = """\
793
+ from __future__ import annotations
794
+ import sys
795
+ from importlib.machinery import ModuleSpec, PathFinder
796
+ from importlib.machinery import all_suffixes as module_suffixes
797
+ from importlib.util import spec_from_file_location
798
+ from itertools import chain
799
+ from pathlib import Path
800
+
801
+ MAPPING: dict[str, str] = {mapping!r}
802
+ NAMESPACES: dict[str, list[str]] = {namespaces!r}
803
+ PATH_PLACEHOLDER = {name!r} + ".__path_hook__"
804
+
805
+
806
+ class _EditableFinder: # MetaPathFinder
807
+ @classmethod
808
+ def find_spec(cls, fullname: str, _path=None, _target=None) -> ModuleSpec | None:
809
+ # Top-level packages and modules (we know these exist in the FS)
810
+ if fullname in MAPPING:
811
+ pkg_path = MAPPING[fullname]
812
+ return cls._find_spec(fullname, Path(pkg_path))
813
+
814
+ # Handle immediate children modules (required for namespaces to work)
815
+ # To avoid problems with case sensitivity in the file system we delegate
816
+ # to the importlib.machinery implementation.
817
+ parent, _, child = fullname.rpartition(".")
818
+ if parent and parent in MAPPING:
819
+ return PathFinder.find_spec(fullname, path=[MAPPING[parent]])
820
+
821
+ # Other levels of nesting should be handled automatically by importlib
822
+ # using the parent path.
823
+ return None
824
+
825
+ @classmethod
826
+ def _find_spec(cls, fullname: str, candidate_path: Path) -> ModuleSpec | None:
827
+ init = candidate_path / "__init__.py"
828
+ candidates = (candidate_path.with_suffix(x) for x in module_suffixes())
829
+ for candidate in chain([init], candidates):
830
+ if candidate.exists():
831
+ return spec_from_file_location(fullname, candidate)
832
+ return None
833
+
834
+
835
+ class _EditableNamespaceFinder: # PathEntryFinder
836
+ @classmethod
837
+ def _path_hook(cls, path) -> type[_EditableNamespaceFinder]:
838
+ if path == PATH_PLACEHOLDER:
839
+ return cls
840
+ raise ImportError
841
+
842
+ @classmethod
843
+ def _paths(cls, fullname: str) -> list[str]:
844
+ paths = NAMESPACES[fullname]
845
+ if not paths and fullname in MAPPING:
846
+ paths = [MAPPING[fullname]]
847
+ # Always add placeholder, for 2 reasons:
848
+ # 1. __path__ cannot be empty for the spec to be considered namespace.
849
+ # 2. In the case of nested namespaces, we need to force
850
+ # import machinery to query _EditableNamespaceFinder again.
851
+ return [*paths, PATH_PLACEHOLDER]
852
+
853
+ @classmethod
854
+ def find_spec(cls, fullname: str, _target=None) -> ModuleSpec | None:
855
+ if fullname in NAMESPACES:
856
+ spec = ModuleSpec(fullname, None, is_package=True)
857
+ spec.submodule_search_locations = cls._paths(fullname)
858
+ return spec
859
+ return None
860
+
861
+ @classmethod
862
+ def find_module(cls, _fullname) -> None:
863
+ return None
864
+
865
+
866
+ def install():
867
+ if not any(finder == _EditableFinder for finder in sys.meta_path):
868
+ sys.meta_path.append(_EditableFinder)
869
+
870
+ if not NAMESPACES:
871
+ return
872
+
873
+ if not any(hook == _EditableNamespaceFinder._path_hook for hook in sys.path_hooks):
874
+ # PathEntryFinder is needed to create NamespaceSpec without private APIS
875
+ sys.path_hooks.append(_EditableNamespaceFinder._path_hook)
876
+ if PATH_PLACEHOLDER not in sys.path:
877
+ sys.path.append(PATH_PLACEHOLDER) # Used just to trigger the path hook
878
+ """
879
+
880
+
881
+ def _finder_template(
882
+ name: str, mapping: Mapping[str, str], namespaces: dict[str, list[str]]
883
+ ) -> str:
884
+ """Create a string containing the code for the``MetaPathFinder`` and
885
+ ``PathEntryFinder``.
886
+ """
887
+ mapping = dict(sorted(mapping.items(), key=lambda p: p[0]))
888
+ return _FINDER_TEMPLATE.format(name=name, mapping=mapping, namespaces=namespaces)
889
+
890
+
891
+ class LinksNotSupported(errors.FileError):
892
+ """File system does not seem to support either symlinks or hard links."""
893
+
894
+
895
+ class _DebuggingTips(SetuptoolsWarning):
896
+ _SUMMARY = "Problem in editable installation."
897
+ _DETAILS = """
898
+ An error happened while installing `{project}` in editable mode.
899
+
900
+ The following steps are recommended to help debug this problem:
901
+
902
+ - Try to install the project normally, without using the editable mode.
903
+ Does the error still persist?
904
+ (If it does, try fixing the problem before attempting the editable mode).
905
+ - If you are using binary extensions, make sure you have all OS-level
906
+ dependencies installed (e.g. compilers, toolchains, binary libraries, ...).
907
+ - Try the latest version of setuptools (maybe the error was already fixed).
908
+ - If you (or your project dependencies) are using any setuptools extension
909
+ or customization, make sure they support the editable mode.
910
+
911
+ After following the steps above, if the problem still persists and
912
+ you think this is related to how setuptools handles editable installations,
913
+ please submit a reproducible example
914
+ (see https://stackoverflow.com/help/minimal-reproducible-example) to:
915
+
916
+ https://github.com/pypa/setuptools/issues
917
+ """
918
+ _SEE_DOCS = "userguide/development_mode.html"
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/egg_info.py ADDED
@@ -0,0 +1,737 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """setuptools.command.egg_info
2
+
3
+ Create a distribution's .egg-info directory and contents"""
4
+
5
+ from distutils.filelist import FileList as _FileList
6
+ from distutils.errors import DistutilsInternalError
7
+ from distutils.util import convert_path
8
+ from distutils import log
9
+ import distutils.errors
10
+ import distutils.filelist
11
+ import functools
12
+ import os
13
+ import re
14
+ import sys
15
+ import time
16
+ import collections
17
+
18
+ from .._importlib import metadata
19
+ from .. import _entry_points, _normalization
20
+ from . import _requirestxt
21
+
22
+ from setuptools import Command
23
+ from setuptools.command.sdist import sdist
24
+ from setuptools.command.sdist import walk_revctrl
25
+ from setuptools.command.setopt import edit_config
26
+ from setuptools.command import bdist_egg
27
+ import setuptools.unicode_utils as unicode_utils
28
+ from setuptools.glob import glob
29
+
30
+ from setuptools.extern import packaging
31
+ from ..warnings import SetuptoolsDeprecationWarning
32
+
33
+
34
+ PY_MAJOR = '{}.{}'.format(*sys.version_info)
35
+
36
+
37
+ def translate_pattern(glob): # noqa: C901 # is too complex (14) # FIXME
38
+ """
39
+ Translate a file path glob like '*.txt' in to a regular expression.
40
+ This differs from fnmatch.translate which allows wildcards to match
41
+ directory separators. It also knows about '**/' which matches any number of
42
+ directories.
43
+ """
44
+ pat = ''
45
+
46
+ # This will split on '/' within [character classes]. This is deliberate.
47
+ chunks = glob.split(os.path.sep)
48
+
49
+ sep = re.escape(os.sep)
50
+ valid_char = '[^%s]' % (sep,)
51
+
52
+ for c, chunk in enumerate(chunks):
53
+ last_chunk = c == len(chunks) - 1
54
+
55
+ # Chunks that are a literal ** are globstars. They match anything.
56
+ if chunk == '**':
57
+ if last_chunk:
58
+ # Match anything if this is the last component
59
+ pat += '.*'
60
+ else:
61
+ # Match '(name/)*'
62
+ pat += '(?:%s+%s)*' % (valid_char, sep)
63
+ continue # Break here as the whole path component has been handled
64
+
65
+ # Find any special characters in the remainder
66
+ i = 0
67
+ chunk_len = len(chunk)
68
+ while i < chunk_len:
69
+ char = chunk[i]
70
+ if char == '*':
71
+ # Match any number of name characters
72
+ pat += valid_char + '*'
73
+ elif char == '?':
74
+ # Match a name character
75
+ pat += valid_char
76
+ elif char == '[':
77
+ # Character class
78
+ inner_i = i + 1
79
+ # Skip initial !/] chars
80
+ if inner_i < chunk_len and chunk[inner_i] == '!':
81
+ inner_i = inner_i + 1
82
+ if inner_i < chunk_len and chunk[inner_i] == ']':
83
+ inner_i = inner_i + 1
84
+
85
+ # Loop till the closing ] is found
86
+ while inner_i < chunk_len and chunk[inner_i] != ']':
87
+ inner_i = inner_i + 1
88
+
89
+ if inner_i >= chunk_len:
90
+ # Got to the end of the string without finding a closing ]
91
+ # Do not treat this as a matching group, but as a literal [
92
+ pat += re.escape(char)
93
+ else:
94
+ # Grab the insides of the [brackets]
95
+ inner = chunk[i + 1 : inner_i]
96
+ char_class = ''
97
+
98
+ # Class negation
99
+ if inner[0] == '!':
100
+ char_class = '^'
101
+ inner = inner[1:]
102
+
103
+ char_class += re.escape(inner)
104
+ pat += '[%s]' % (char_class,)
105
+
106
+ # Skip to the end ]
107
+ i = inner_i
108
+ else:
109
+ pat += re.escape(char)
110
+ i += 1
111
+
112
+ # Join each chunk with the dir separator
113
+ if not last_chunk:
114
+ pat += sep
115
+
116
+ pat += r'\Z'
117
+ return re.compile(pat, flags=re.MULTILINE | re.DOTALL)
118
+
119
+
120
+ class InfoCommon:
121
+ tag_build = None
122
+ tag_date = None
123
+
124
+ @property
125
+ def name(self):
126
+ return _normalization.safe_name(self.distribution.get_name())
127
+
128
+ def tagged_version(self):
129
+ tagged = self._maybe_tag(self.distribution.get_version())
130
+ return _normalization.safe_version(tagged)
131
+
132
+ def _maybe_tag(self, version):
133
+ """
134
+ egg_info may be called more than once for a distribution,
135
+ in which case the version string already contains all tags.
136
+ """
137
+ return (
138
+ version
139
+ if self.vtags and self._already_tagged(version)
140
+ else version + self.vtags
141
+ )
142
+
143
+ def _already_tagged(self, version: str) -> bool:
144
+ # Depending on their format, tags may change with version normalization.
145
+ # So in addition the regular tags, we have to search for the normalized ones.
146
+ return version.endswith(self.vtags) or version.endswith(self._safe_tags())
147
+
148
+ def _safe_tags(self) -> str:
149
+ # To implement this we can rely on `safe_version` pretending to be version 0
150
+ # followed by tags. Then we simply discard the starting 0 (fake version number)
151
+ try:
152
+ return _normalization.safe_version(f"0{self.vtags}")[1:]
153
+ except packaging.version.InvalidVersion:
154
+ return _normalization.safe_name(self.vtags.replace(' ', '.'))
155
+
156
+ def tags(self) -> str:
157
+ version = ''
158
+ if self.tag_build:
159
+ version += self.tag_build
160
+ if self.tag_date:
161
+ version += time.strftime("%Y%m%d")
162
+ return version
163
+
164
+ vtags = property(tags)
165
+
166
+
167
+ class egg_info(InfoCommon, Command):
168
+ description = "create a distribution's .egg-info directory"
169
+
170
+ user_options = [
171
+ (
172
+ 'egg-base=',
173
+ 'e',
174
+ "directory containing .egg-info directories"
175
+ " [default: top of the source tree]",
176
+ ),
177
+ ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"),
178
+ ('tag-build=', 'b', "Specify explicit tag to add to version number"),
179
+ ('no-date', 'D', "Don't include date stamp [default]"),
180
+ ]
181
+
182
+ boolean_options = ['tag-date']
183
+ negative_opt = {
184
+ 'no-date': 'tag-date',
185
+ }
186
+
187
+ def initialize_options(self):
188
+ self.egg_base = None
189
+ self.egg_name = None
190
+ self.egg_info = None
191
+ self.egg_version = None
192
+ self.ignore_egg_info_in_manifest = False
193
+
194
+ ####################################
195
+ # allow the 'tag_svn_revision' to be detected and
196
+ # set, supporting sdists built on older Setuptools.
197
+ @property
198
+ def tag_svn_revision(self):
199
+ pass
200
+
201
+ @tag_svn_revision.setter
202
+ def tag_svn_revision(self, value):
203
+ pass
204
+
205
+ ####################################
206
+
207
+ def save_version_info(self, filename):
208
+ """
209
+ Materialize the value of date into the
210
+ build tag. Install build keys in a deterministic order
211
+ to avoid arbitrary reordering on subsequent builds.
212
+ """
213
+ egg_info = collections.OrderedDict()
214
+ # follow the order these keys would have been added
215
+ # when PYTHONHASHSEED=0
216
+ egg_info['tag_build'] = self.tags()
217
+ egg_info['tag_date'] = 0
218
+ edit_config(filename, dict(egg_info=egg_info))
219
+
220
+ def finalize_options(self):
221
+ # Note: we need to capture the current value returned
222
+ # by `self.tagged_version()`, so we can later update
223
+ # `self.distribution.metadata.version` without
224
+ # repercussions.
225
+ self.egg_name = self.name
226
+ self.egg_version = self.tagged_version()
227
+ parsed_version = packaging.version.Version(self.egg_version)
228
+
229
+ try:
230
+ is_version = isinstance(parsed_version, packaging.version.Version)
231
+ spec = "%s==%s" if is_version else "%s===%s"
232
+ packaging.requirements.Requirement(spec % (self.egg_name, self.egg_version))
233
+ except ValueError as e:
234
+ raise distutils.errors.DistutilsOptionError(
235
+ "Invalid distribution name or version syntax: %s-%s"
236
+ % (self.egg_name, self.egg_version)
237
+ ) from e
238
+
239
+ if self.egg_base is None:
240
+ dirs = self.distribution.package_dir
241
+ self.egg_base = (dirs or {}).get('', os.curdir)
242
+
243
+ self.ensure_dirname('egg_base')
244
+ self.egg_info = _normalization.filename_component(self.egg_name) + '.egg-info'
245
+ if self.egg_base != os.curdir:
246
+ self.egg_info = os.path.join(self.egg_base, self.egg_info)
247
+
248
+ # Set package version for the benefit of dumber commands
249
+ # (e.g. sdist, bdist_wininst, etc.)
250
+ #
251
+ self.distribution.metadata.version = self.egg_version
252
+
253
+ # If we bootstrapped around the lack of a PKG-INFO, as might be the
254
+ # case in a fresh checkout, make sure that any special tags get added
255
+ # to the version info
256
+ #
257
+ pd = self.distribution._patched_dist
258
+ key = getattr(pd, "key", None) or getattr(pd, "name", None)
259
+ if pd is not None and key == self.egg_name.lower():
260
+ pd._version = self.egg_version
261
+ pd._parsed_version = packaging.version.Version(self.egg_version)
262
+ self.distribution._patched_dist = None
263
+
264
+ def _get_egg_basename(self, py_version=PY_MAJOR, platform=None):
265
+ """Compute filename of the output egg. Private API."""
266
+ return _egg_basename(self.egg_name, self.egg_version, py_version, platform)
267
+
268
+ def write_or_delete_file(self, what, filename, data, force=False):
269
+ """Write `data` to `filename` or delete if empty
270
+
271
+ If `data` is non-empty, this routine is the same as ``write_file()``.
272
+ If `data` is empty but not ``None``, this is the same as calling
273
+ ``delete_file(filename)`. If `data` is ``None``, then this is a no-op
274
+ unless `filename` exists, in which case a warning is issued about the
275
+ orphaned file (if `force` is false), or deleted (if `force` is true).
276
+ """
277
+ if data:
278
+ self.write_file(what, filename, data)
279
+ elif os.path.exists(filename):
280
+ if data is None and not force:
281
+ log.warn("%s not set in setup(), but %s exists", what, filename)
282
+ return
283
+ else:
284
+ self.delete_file(filename)
285
+
286
+ def write_file(self, what, filename, data):
287
+ """Write `data` to `filename` (if not a dry run) after announcing it
288
+
289
+ `what` is used in a log message to identify what is being written
290
+ to the file.
291
+ """
292
+ log.info("writing %s to %s", what, filename)
293
+ data = data.encode("utf-8")
294
+ if not self.dry_run:
295
+ f = open(filename, 'wb')
296
+ f.write(data)
297
+ f.close()
298
+
299
+ def delete_file(self, filename):
300
+ """Delete `filename` (if not a dry run) after announcing it"""
301
+ log.info("deleting %s", filename)
302
+ if not self.dry_run:
303
+ os.unlink(filename)
304
+
305
+ def run(self):
306
+ self.mkpath(self.egg_info)
307
+ try:
308
+ os.utime(self.egg_info, None)
309
+ except OSError as e:
310
+ msg = f"Cannot update time stamp of directory '{self.egg_info}'"
311
+ raise distutils.errors.DistutilsFileError(msg) from e
312
+ for ep in metadata.entry_points(group='egg_info.writers'):
313
+ writer = ep.load()
314
+ writer(self, ep.name, os.path.join(self.egg_info, ep.name))
315
+
316
+ # Get rid of native_libs.txt if it was put there by older bdist_egg
317
+ nl = os.path.join(self.egg_info, "native_libs.txt")
318
+ if os.path.exists(nl):
319
+ self.delete_file(nl)
320
+
321
+ self.find_sources()
322
+
323
+ def find_sources(self):
324
+ """Generate SOURCES.txt manifest file"""
325
+ manifest_filename = os.path.join(self.egg_info, "SOURCES.txt")
326
+ mm = manifest_maker(self.distribution)
327
+ mm.ignore_egg_info_dir = self.ignore_egg_info_in_manifest
328
+ mm.manifest = manifest_filename
329
+ mm.run()
330
+ self.filelist = mm.filelist
331
+
332
+
333
+ class FileList(_FileList):
334
+ # Implementations of the various MANIFEST.in commands
335
+
336
+ def __init__(self, warn=None, debug_print=None, ignore_egg_info_dir=False):
337
+ super().__init__(warn, debug_print)
338
+ self.ignore_egg_info_dir = ignore_egg_info_dir
339
+
340
+ def process_template_line(self, line):
341
+ # Parse the line: split it up, make sure the right number of words
342
+ # is there, and return the relevant words. 'action' is always
343
+ # defined: it's the first word of the line. Which of the other
344
+ # three are defined depends on the action; it'll be either
345
+ # patterns, (dir and patterns), or (dir_pattern).
346
+ (action, patterns, dir, dir_pattern) = self._parse_template_line(line)
347
+
348
+ action_map = {
349
+ 'include': self.include,
350
+ 'exclude': self.exclude,
351
+ 'global-include': self.global_include,
352
+ 'global-exclude': self.global_exclude,
353
+ 'recursive-include': functools.partial(
354
+ self.recursive_include,
355
+ dir,
356
+ ),
357
+ 'recursive-exclude': functools.partial(
358
+ self.recursive_exclude,
359
+ dir,
360
+ ),
361
+ 'graft': self.graft,
362
+ 'prune': self.prune,
363
+ }
364
+ log_map = {
365
+ 'include': "warning: no files found matching '%s'",
366
+ 'exclude': ("warning: no previously-included files found matching '%s'"),
367
+ 'global-include': (
368
+ "warning: no files found matching '%s' anywhere in distribution"
369
+ ),
370
+ 'global-exclude': (
371
+ "warning: no previously-included files matching "
372
+ "'%s' found anywhere in distribution"
373
+ ),
374
+ 'recursive-include': (
375
+ "warning: no files found matching '%s' under directory '%s'"
376
+ ),
377
+ 'recursive-exclude': (
378
+ "warning: no previously-included files matching "
379
+ "'%s' found under directory '%s'"
380
+ ),
381
+ 'graft': "warning: no directories found matching '%s'",
382
+ 'prune': "no previously-included directories found matching '%s'",
383
+ }
384
+
385
+ try:
386
+ process_action = action_map[action]
387
+ except KeyError:
388
+ msg = f"Invalid MANIFEST.in: unknown action {action!r} in {line!r}"
389
+ raise DistutilsInternalError(msg) from None
390
+
391
+ # OK, now we know that the action is valid and we have the
392
+ # right number of words on the line for that action -- so we
393
+ # can proceed with minimal error-checking.
394
+
395
+ action_is_recursive = action.startswith('recursive-')
396
+ if action in {'graft', 'prune'}:
397
+ patterns = [dir_pattern]
398
+ extra_log_args = (dir,) if action_is_recursive else ()
399
+ log_tmpl = log_map[action]
400
+
401
+ self.debug_print(
402
+ ' '.join(
403
+ [action] + ([dir] if action_is_recursive else []) + patterns,
404
+ )
405
+ )
406
+ for pattern in patterns:
407
+ if not process_action(pattern):
408
+ log.warn(log_tmpl, pattern, *extra_log_args)
409
+
410
+ def _remove_files(self, predicate):
411
+ """
412
+ Remove all files from the file list that match the predicate.
413
+ Return True if any matching files were removed
414
+ """
415
+ found = False
416
+ for i in range(len(self.files) - 1, -1, -1):
417
+ if predicate(self.files[i]):
418
+ self.debug_print(" removing " + self.files[i])
419
+ del self.files[i]
420
+ found = True
421
+ return found
422
+
423
+ def include(self, pattern):
424
+ """Include files that match 'pattern'."""
425
+ found = [f for f in glob(pattern) if not os.path.isdir(f)]
426
+ self.extend(found)
427
+ return bool(found)
428
+
429
+ def exclude(self, pattern):
430
+ """Exclude files that match 'pattern'."""
431
+ match = translate_pattern(pattern)
432
+ return self._remove_files(match.match)
433
+
434
+ def recursive_include(self, dir, pattern):
435
+ """
436
+ Include all files anywhere in 'dir/' that match the pattern.
437
+ """
438
+ full_pattern = os.path.join(dir, '**', pattern)
439
+ found = [f for f in glob(full_pattern, recursive=True) if not os.path.isdir(f)]
440
+ self.extend(found)
441
+ return bool(found)
442
+
443
+ def recursive_exclude(self, dir, pattern):
444
+ """
445
+ Exclude any file anywhere in 'dir/' that match the pattern.
446
+ """
447
+ match = translate_pattern(os.path.join(dir, '**', pattern))
448
+ return self._remove_files(match.match)
449
+
450
+ def graft(self, dir):
451
+ """Include all files from 'dir/'."""
452
+ found = [
453
+ item
454
+ for match_dir in glob(dir)
455
+ for item in distutils.filelist.findall(match_dir)
456
+ ]
457
+ self.extend(found)
458
+ return bool(found)
459
+
460
+ def prune(self, dir):
461
+ """Filter out files from 'dir/'."""
462
+ match = translate_pattern(os.path.join(dir, '**'))
463
+ return self._remove_files(match.match)
464
+
465
+ def global_include(self, pattern):
466
+ """
467
+ Include all files anywhere in the current directory that match the
468
+ pattern. This is very inefficient on large file trees.
469
+ """
470
+ if self.allfiles is None:
471
+ self.findall()
472
+ match = translate_pattern(os.path.join('**', pattern))
473
+ found = [f for f in self.allfiles if match.match(f)]
474
+ self.extend(found)
475
+ return bool(found)
476
+
477
+ def global_exclude(self, pattern):
478
+ """
479
+ Exclude all files anywhere that match the pattern.
480
+ """
481
+ match = translate_pattern(os.path.join('**', pattern))
482
+ return self._remove_files(match.match)
483
+
484
+ def append(self, item):
485
+ if item.endswith('\r'): # Fix older sdists built on Windows
486
+ item = item[:-1]
487
+ path = convert_path(item)
488
+
489
+ if self._safe_path(path):
490
+ self.files.append(path)
491
+
492
+ def extend(self, paths):
493
+ self.files.extend(filter(self._safe_path, paths))
494
+
495
+ def _repair(self):
496
+ """
497
+ Replace self.files with only safe paths
498
+
499
+ Because some owners of FileList manipulate the underlying
500
+ ``files`` attribute directly, this method must be called to
501
+ repair those paths.
502
+ """
503
+ self.files = list(filter(self._safe_path, self.files))
504
+
505
+ def _safe_path(self, path):
506
+ enc_warn = "'%s' not %s encodable -- skipping"
507
+
508
+ # To avoid accidental trans-codings errors, first to unicode
509
+ u_path = unicode_utils.filesys_decode(path)
510
+ if u_path is None:
511
+ log.warn("'%s' in unexpected encoding -- skipping" % path)
512
+ return False
513
+
514
+ # Must ensure utf-8 encodability
515
+ utf8_path = unicode_utils.try_encode(u_path, "utf-8")
516
+ if utf8_path is None:
517
+ log.warn(enc_warn, path, 'utf-8')
518
+ return False
519
+
520
+ try:
521
+ # ignore egg-info paths
522
+ is_egg_info = ".egg-info" in u_path or b".egg-info" in utf8_path
523
+ if self.ignore_egg_info_dir and is_egg_info:
524
+ return False
525
+ # accept is either way checks out
526
+ if os.path.exists(u_path) or os.path.exists(utf8_path):
527
+ return True
528
+ # this will catch any encode errors decoding u_path
529
+ except UnicodeEncodeError:
530
+ log.warn(enc_warn, path, sys.getfilesystemencoding())
531
+
532
+
533
+ class manifest_maker(sdist):
534
+ template = "MANIFEST.in"
535
+
536
+ def initialize_options(self):
537
+ self.use_defaults = True
538
+ self.prune = True
539
+ self.manifest_only = True
540
+ self.force_manifest = True
541
+ self.ignore_egg_info_dir = False
542
+
543
+ def finalize_options(self):
544
+ pass
545
+
546
+ def run(self):
547
+ self.filelist = FileList(ignore_egg_info_dir=self.ignore_egg_info_dir)
548
+ if not os.path.exists(self.manifest):
549
+ self.write_manifest() # it must exist so it'll get in the list
550
+ self.add_defaults()
551
+ if os.path.exists(self.template):
552
+ self.read_template()
553
+ self.add_license_files()
554
+ self._add_referenced_files()
555
+ self.prune_file_list()
556
+ self.filelist.sort()
557
+ self.filelist.remove_duplicates()
558
+ self.write_manifest()
559
+
560
+ def _manifest_normalize(self, path):
561
+ path = unicode_utils.filesys_decode(path)
562
+ return path.replace(os.sep, '/')
563
+
564
+ def write_manifest(self):
565
+ """
566
+ Write the file list in 'self.filelist' to the manifest file
567
+ named by 'self.manifest'.
568
+ """
569
+ self.filelist._repair()
570
+
571
+ # Now _repairs should encodability, but not unicode
572
+ files = [self._manifest_normalize(f) for f in self.filelist.files]
573
+ msg = "writing manifest file '%s'" % self.manifest
574
+ self.execute(write_file, (self.manifest, files), msg)
575
+
576
+ def warn(self, msg):
577
+ if not self._should_suppress_warning(msg):
578
+ sdist.warn(self, msg)
579
+
580
+ @staticmethod
581
+ def _should_suppress_warning(msg):
582
+ """
583
+ suppress missing-file warnings from sdist
584
+ """
585
+ return re.match(r"standard file .*not found", msg)
586
+
587
+ def add_defaults(self):
588
+ sdist.add_defaults(self)
589
+ self.filelist.append(self.template)
590
+ self.filelist.append(self.manifest)
591
+ rcfiles = list(walk_revctrl())
592
+ if rcfiles:
593
+ self.filelist.extend(rcfiles)
594
+ elif os.path.exists(self.manifest):
595
+ self.read_manifest()
596
+
597
+ if os.path.exists("setup.py"):
598
+ # setup.py should be included by default, even if it's not
599
+ # the script called to create the sdist
600
+ self.filelist.append("setup.py")
601
+
602
+ ei_cmd = self.get_finalized_command('egg_info')
603
+ self.filelist.graft(ei_cmd.egg_info)
604
+
605
+ def add_license_files(self):
606
+ license_files = self.distribution.metadata.license_files or []
607
+ for lf in license_files:
608
+ log.info("adding license file '%s'", lf)
609
+ self.filelist.extend(license_files)
610
+
611
+ def _add_referenced_files(self):
612
+ """Add files referenced by the config (e.g. `file:` directive) to filelist"""
613
+ referenced = getattr(self.distribution, '_referenced_files', [])
614
+ # ^-- fallback if dist comes from distutils or is a custom class
615
+ for rf in referenced:
616
+ log.debug("adding file referenced by config '%s'", rf)
617
+ self.filelist.extend(referenced)
618
+
619
+ def prune_file_list(self):
620
+ build = self.get_finalized_command('build')
621
+ base_dir = self.distribution.get_fullname()
622
+ self.filelist.prune(build.build_base)
623
+ self.filelist.prune(base_dir)
624
+ sep = re.escape(os.sep)
625
+ self.filelist.exclude_pattern(
626
+ r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, is_regex=True
627
+ )
628
+
629
+ def _safe_data_files(self, build_py):
630
+ """
631
+ The parent class implementation of this method
632
+ (``sdist``) will try to include data files, which
633
+ might cause recursion problems when
634
+ ``include_package_data=True``.
635
+
636
+ Therefore, avoid triggering any attempt of
637
+ analyzing/building the manifest again.
638
+ """
639
+ if hasattr(build_py, 'get_data_files_without_manifest'):
640
+ return build_py.get_data_files_without_manifest()
641
+
642
+ SetuptoolsDeprecationWarning.emit(
643
+ "`build_py` command does not inherit from setuptools' `build_py`.",
644
+ """
645
+ Custom 'build_py' does not implement 'get_data_files_without_manifest'.
646
+ Please extend command classes from setuptools instead of distutils.
647
+ """,
648
+ see_url="https://peps.python.org/pep-0632/",
649
+ # due_date not defined yet, old projects might still do it?
650
+ )
651
+ return build_py.get_data_files()
652
+
653
+
654
+ def write_file(filename, contents):
655
+ """Create a file with the specified name and write 'contents' (a
656
+ sequence of strings without line terminators) to it.
657
+ """
658
+ contents = "\n".join(contents)
659
+
660
+ # assuming the contents has been vetted for utf-8 encoding
661
+ contents = contents.encode("utf-8")
662
+
663
+ with open(filename, "wb") as f: # always write POSIX-style manifest
664
+ f.write(contents)
665
+
666
+
667
+ def write_pkg_info(cmd, basename, filename):
668
+ log.info("writing %s", filename)
669
+ if not cmd.dry_run:
670
+ metadata = cmd.distribution.metadata
671
+ metadata.version, oldver = cmd.egg_version, metadata.version
672
+ metadata.name, oldname = cmd.egg_name, metadata.name
673
+
674
+ try:
675
+ # write unescaped data to PKG-INFO, so older pkg_resources
676
+ # can still parse it
677
+ metadata.write_pkg_info(cmd.egg_info)
678
+ finally:
679
+ metadata.name, metadata.version = oldname, oldver
680
+
681
+ safe = getattr(cmd.distribution, 'zip_safe', None)
682
+
683
+ bdist_egg.write_safety_flag(cmd.egg_info, safe)
684
+
685
+
686
+ def warn_depends_obsolete(cmd, basename, filename):
687
+ """
688
+ Unused: left to avoid errors when updating (from source) from <= 67.8.
689
+ Old installations have a .dist-info directory with the entry-point
690
+ ``depends.txt = setuptools.command.egg_info:warn_depends_obsolete``.
691
+ This may trigger errors when running the first egg_info in build_meta.
692
+ TODO: Remove this function in a version sufficiently > 68.
693
+ """
694
+
695
+
696
+ # Export API used in entry_points
697
+ write_requirements = _requirestxt.write_requirements
698
+ write_setup_requirements = _requirestxt.write_setup_requirements
699
+
700
+
701
+ def write_toplevel_names(cmd, basename, filename):
702
+ pkgs = dict.fromkeys([
703
+ k.split('.', 1)[0] for k in cmd.distribution.iter_distribution_names()
704
+ ])
705
+ cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n')
706
+
707
+
708
+ def overwrite_arg(cmd, basename, filename):
709
+ write_arg(cmd, basename, filename, True)
710
+
711
+
712
+ def write_arg(cmd, basename, filename, force=False):
713
+ argname = os.path.splitext(basename)[0]
714
+ value = getattr(cmd.distribution, argname, None)
715
+ if value is not None:
716
+ value = '\n'.join(value) + '\n'
717
+ cmd.write_or_delete_file(argname, filename, value, force)
718
+
719
+
720
+ def write_entries(cmd, basename, filename):
721
+ eps = _entry_points.load(cmd.distribution.entry_points)
722
+ defn = _entry_points.render(eps)
723
+ cmd.write_or_delete_file('entry points', filename, defn, True)
724
+
725
+
726
+ def _egg_basename(egg_name, egg_version, py_version=None, platform=None):
727
+ """Compute filename of the output egg. Private API."""
728
+ name = _normalization.filename_component(egg_name)
729
+ version = _normalization.filename_component(egg_version)
730
+ egg = f"{name}-{version}-py{py_version or PY_MAJOR}"
731
+ if platform:
732
+ egg += f"-{platform}"
733
+ return egg
734
+
735
+
736
+ class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning):
737
+ """Deprecated behavior warning for EggInfo, bypassing suppression."""
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/install_lib.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ from itertools import product, starmap
4
+ import distutils.command.install_lib as orig
5
+ from .._path import StrPath
6
+
7
+
8
+ class install_lib(orig.install_lib):
9
+ """Don't add compiled flags to filenames of non-Python files"""
10
+
11
+ def run(self):
12
+ self.build()
13
+ outfiles = self.install()
14
+ if outfiles is not None:
15
+ # always compile, in case we have any extension stubs to deal with
16
+ self.byte_compile(outfiles)
17
+
18
+ def get_exclusions(self):
19
+ """
20
+ Return a collections.Sized collections.Container of paths to be
21
+ excluded for single_version_externally_managed installations.
22
+ """
23
+ all_packages = (
24
+ pkg
25
+ for ns_pkg in self._get_SVEM_NSPs()
26
+ for pkg in self._all_packages(ns_pkg)
27
+ )
28
+
29
+ excl_specs = product(all_packages, self._gen_exclusion_paths())
30
+ return set(starmap(self._exclude_pkg_path, excl_specs))
31
+
32
+ def _exclude_pkg_path(self, pkg, exclusion_path):
33
+ """
34
+ Given a package name and exclusion path within that package,
35
+ compute the full exclusion path.
36
+ """
37
+ parts = pkg.split('.') + [exclusion_path]
38
+ return os.path.join(self.install_dir, *parts)
39
+
40
+ @staticmethod
41
+ def _all_packages(pkg_name):
42
+ """
43
+ >>> list(install_lib._all_packages('foo.bar.baz'))
44
+ ['foo.bar.baz', 'foo.bar', 'foo']
45
+ """
46
+ while pkg_name:
47
+ yield pkg_name
48
+ pkg_name, sep, child = pkg_name.rpartition('.')
49
+
50
+ def _get_SVEM_NSPs(self):
51
+ """
52
+ Get namespace packages (list) but only for
53
+ single_version_externally_managed installations and empty otherwise.
54
+ """
55
+ # TODO: is it necessary to short-circuit here? i.e. what's the cost
56
+ # if get_finalized_command is called even when namespace_packages is
57
+ # False?
58
+ if not self.distribution.namespace_packages:
59
+ return []
60
+
61
+ install_cmd = self.get_finalized_command('install')
62
+ svem = install_cmd.single_version_externally_managed
63
+
64
+ return self.distribution.namespace_packages if svem else []
65
+
66
+ @staticmethod
67
+ def _gen_exclusion_paths():
68
+ """
69
+ Generate file paths to be excluded for namespace packages (bytecode
70
+ cache files).
71
+ """
72
+ # always exclude the package module itself
73
+ yield '__init__.py'
74
+
75
+ yield '__init__.pyc'
76
+ yield '__init__.pyo'
77
+
78
+ if not hasattr(sys, 'implementation'):
79
+ return
80
+
81
+ base = os.path.join('__pycache__', '__init__.' + sys.implementation.cache_tag)
82
+ yield base + '.pyc'
83
+ yield base + '.pyo'
84
+ yield base + '.opt-1.pyc'
85
+ yield base + '.opt-2.pyc'
86
+
87
+ def copy_tree(
88
+ self,
89
+ infile: StrPath,
90
+ outfile: str,
91
+ preserve_mode=True,
92
+ preserve_times=True,
93
+ preserve_symlinks=False,
94
+ level=1,
95
+ ):
96
+ assert preserve_mode and preserve_times and not preserve_symlinks
97
+ exclude = self.get_exclusions()
98
+
99
+ if not exclude:
100
+ return orig.install_lib.copy_tree(self, infile, outfile) # type: ignore[arg-type] # Fixed upstream
101
+
102
+ # Exclude namespace package __init__.py* files from the output
103
+
104
+ from setuptools.archive_util import unpack_directory
105
+ from distutils import log
106
+
107
+ outfiles = []
108
+
109
+ def pf(src, dst):
110
+ if dst in exclude:
111
+ log.warn("Skipping installation of %s (namespace package)", dst)
112
+ return False
113
+
114
+ log.info("copying %s -> %s", src, os.path.dirname(dst))
115
+ outfiles.append(dst)
116
+ return dst
117
+
118
+ unpack_directory(infile, outfile, pf)
119
+ return outfiles
120
+
121
+ def get_outputs(self):
122
+ outputs = orig.install_lib.get_outputs(self)
123
+ exclude = self.get_exclusions()
124
+ if exclude:
125
+ return [f for f in outputs if f not in exclude]
126
+ return outputs
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/install_scripts.py ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from distutils import log
4
+ import distutils.command.install_scripts as orig
5
+ import os
6
+ import sys
7
+
8
+ from .._path import ensure_directory
9
+
10
+
11
+ class install_scripts(orig.install_scripts):
12
+ """Do normal script install, plus any egg_info wrapper scripts"""
13
+
14
+ def initialize_options(self):
15
+ orig.install_scripts.initialize_options(self)
16
+ self.no_ep = False
17
+
18
+ def run(self) -> None:
19
+ self.run_command("egg_info")
20
+ if self.distribution.scripts:
21
+ orig.install_scripts.run(self) # run first to set up self.outfiles
22
+ else:
23
+ self.outfiles: list[str] = []
24
+ if self.no_ep:
25
+ # don't install entry point scripts into .egg file!
26
+ return
27
+ self._install_ep_scripts()
28
+
29
+ def _install_ep_scripts(self):
30
+ # Delay import side-effects
31
+ from pkg_resources import Distribution, PathMetadata
32
+ from . import easy_install as ei
33
+
34
+ ei_cmd = self.get_finalized_command("egg_info")
35
+ dist = Distribution(
36
+ ei_cmd.egg_base,
37
+ PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info),
38
+ ei_cmd.egg_name,
39
+ ei_cmd.egg_version,
40
+ )
41
+ bs_cmd = self.get_finalized_command('build_scripts')
42
+ exec_param = getattr(bs_cmd, 'executable', None)
43
+ writer = ei.ScriptWriter
44
+ if exec_param == sys.executable:
45
+ # In case the path to the Python executable contains a space, wrap
46
+ # it so it's not split up.
47
+ exec_param = [exec_param]
48
+ # resolve the writer to the environment
49
+ writer = writer.best()
50
+ cmd = writer.command_spec_class.best().from_param(exec_param)
51
+ for args in writer.get_args(dist, cmd.as_header()):
52
+ self.write_script(*args)
53
+
54
+ def write_script(self, script_name, contents, mode="t", *ignored):
55
+ """Write an executable file to the scripts directory"""
56
+ from setuptools.command.easy_install import chmod, current_umask
57
+
58
+ log.info("Installing %s script to %s", script_name, self.install_dir)
59
+ target = os.path.join(self.install_dir, script_name)
60
+ self.outfiles.append(target)
61
+
62
+ encoding = None if "b" in mode else "utf-8"
63
+ mask = current_umask()
64
+ if not self.dry_run:
65
+ ensure_directory(target)
66
+ with open(target, "w" + mode, encoding=encoding) as f:
67
+ f.write(contents)
68
+ chmod(target, 0o777 - mask)
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/launcher manifest.xml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2
+ <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
3
+ <assemblyIdentity version="1.0.0.0"
4
+ processorArchitecture="X86"
5
+ name="%(name)s"
6
+ type="win32"/>
7
+ <!-- Identify the application security requirements. -->
8
+ <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
9
+ <security>
10
+ <requestedPrivileges>
11
+ <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
12
+ </requestedPrivileges>
13
+ </security>
14
+ </trustInfo>
15
+ </assembly>
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/register.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from distutils import log
2
+ import distutils.command.register as orig
3
+
4
+ from setuptools.errors import RemovedCommandError
5
+
6
+
7
+ class register(orig.register):
8
+ """Formerly used to register packages on PyPI."""
9
+
10
+ def run(self):
11
+ msg = (
12
+ "The register command has been removed, use twine to upload "
13
+ "instead (https://pypi.org/p/twine)"
14
+ )
15
+
16
+ self.announce("ERROR: " + msg, log.ERROR)
17
+
18
+ raise RemovedCommandError(msg)
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/rotate.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from distutils.util import convert_path
4
+ from distutils import log
5
+ from distutils.errors import DistutilsOptionError
6
+ import os
7
+ import shutil
8
+
9
+ from setuptools import Command
10
+
11
+
12
+ class rotate(Command):
13
+ """Delete older distributions"""
14
+
15
+ description = "delete older distributions, keeping N newest files"
16
+ user_options = [
17
+ ('match=', 'm', "patterns to match (required)"),
18
+ ('dist-dir=', 'd', "directory where the distributions are"),
19
+ ('keep=', 'k', "number of matching distributions to keep"),
20
+ ]
21
+
22
+ boolean_options: list[str] = []
23
+
24
+ def initialize_options(self):
25
+ self.match = None
26
+ self.dist_dir = None
27
+ self.keep = None
28
+
29
+ def finalize_options(self):
30
+ if self.match is None:
31
+ raise DistutilsOptionError(
32
+ "Must specify one or more (comma-separated) match patterns "
33
+ "(e.g. '.zip' or '.egg')"
34
+ )
35
+ if self.keep is None:
36
+ raise DistutilsOptionError("Must specify number of files to keep")
37
+ try:
38
+ self.keep = int(self.keep)
39
+ except ValueError as e:
40
+ raise DistutilsOptionError("--keep must be an integer") from e
41
+ if isinstance(self.match, str):
42
+ self.match = [convert_path(p.strip()) for p in self.match.split(',')]
43
+ self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
44
+
45
+ def run(self):
46
+ self.run_command("egg_info")
47
+ from glob import glob
48
+
49
+ for pattern in self.match:
50
+ pattern = self.distribution.get_name() + '*' + pattern
51
+ files = glob(os.path.join(self.dist_dir, pattern))
52
+ files = [(os.path.getmtime(f), f) for f in files]
53
+ files.sort()
54
+ files.reverse()
55
+
56
+ log.info("%d file(s) matching %s", len(files), pattern)
57
+ files = files[self.keep :]
58
+ for t, f in files:
59
+ log.info("Deleting %s", f)
60
+ if not self.dry_run:
61
+ if os.path.isdir(f):
62
+ shutil.rmtree(f)
63
+ else:
64
+ os.unlink(f)
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/sdist.py ADDED
@@ -0,0 +1,204 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from distutils import log
2
+ import distutils.command.sdist as orig
3
+ import os
4
+ import contextlib
5
+ from itertools import chain
6
+
7
+ from .._importlib import metadata
8
+ from .build import _ORIGINAL_SUBCOMMANDS
9
+
10
+ _default_revctrl = list
11
+
12
+
13
+ def walk_revctrl(dirname=''):
14
+ """Find all files under revision control"""
15
+ for ep in metadata.entry_points(group='setuptools.file_finders'):
16
+ yield from ep.load()(dirname)
17
+
18
+
19
+ class sdist(orig.sdist):
20
+ """Smart sdist that finds anything supported by revision control"""
21
+
22
+ user_options = [
23
+ ('formats=', None, "formats for source distribution (comma-separated list)"),
24
+ (
25
+ 'keep-temp',
26
+ 'k',
27
+ "keep the distribution tree around after creating " + "archive file(s)",
28
+ ),
29
+ (
30
+ 'dist-dir=',
31
+ 'd',
32
+ "directory to put the source distribution archive(s) in [default: dist]",
33
+ ),
34
+ (
35
+ 'owner=',
36
+ 'u',
37
+ "Owner name used when creating a tar file [default: current user]",
38
+ ),
39
+ (
40
+ 'group=',
41
+ 'g',
42
+ "Group name used when creating a tar file [default: current group]",
43
+ ),
44
+ ]
45
+
46
+ negative_opt = {}
47
+
48
+ README_EXTENSIONS = ['', '.rst', '.txt', '.md']
49
+ READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS)
50
+
51
+ def run(self):
52
+ self.run_command('egg_info')
53
+ ei_cmd = self.get_finalized_command('egg_info')
54
+ self.filelist = ei_cmd.filelist
55
+ self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt'))
56
+ self.check_readme()
57
+
58
+ # Run sub commands
59
+ for cmd_name in self.get_sub_commands():
60
+ self.run_command(cmd_name)
61
+
62
+ self.make_distribution()
63
+
64
+ dist_files = getattr(self.distribution, 'dist_files', [])
65
+ for file in self.archive_files:
66
+ data = ('sdist', '', file)
67
+ if data not in dist_files:
68
+ dist_files.append(data)
69
+
70
+ def initialize_options(self):
71
+ orig.sdist.initialize_options(self)
72
+
73
+ def make_distribution(self):
74
+ """
75
+ Workaround for #516
76
+ """
77
+ with self._remove_os_link():
78
+ orig.sdist.make_distribution(self)
79
+
80
+ @staticmethod
81
+ @contextlib.contextmanager
82
+ def _remove_os_link():
83
+ """
84
+ In a context, remove and restore os.link if it exists
85
+ """
86
+
87
+ class NoValue:
88
+ pass
89
+
90
+ orig_val = getattr(os, 'link', NoValue)
91
+ try:
92
+ del os.link
93
+ except Exception:
94
+ pass
95
+ try:
96
+ yield
97
+ finally:
98
+ if orig_val is not NoValue:
99
+ os.link = orig_val
100
+
101
+ def add_defaults(self):
102
+ super().add_defaults()
103
+ self._add_defaults_build_sub_commands()
104
+
105
+ def _add_defaults_optional(self):
106
+ super()._add_defaults_optional()
107
+ if os.path.isfile('pyproject.toml'):
108
+ self.filelist.append('pyproject.toml')
109
+
110
+ def _add_defaults_python(self):
111
+ """getting python files"""
112
+ if self.distribution.has_pure_modules():
113
+ build_py = self.get_finalized_command('build_py')
114
+ self.filelist.extend(build_py.get_source_files())
115
+ self._add_data_files(self._safe_data_files(build_py))
116
+
117
+ def _add_defaults_build_sub_commands(self):
118
+ build = self.get_finalized_command("build")
119
+ missing_cmds = set(build.get_sub_commands()) - _ORIGINAL_SUBCOMMANDS
120
+ # ^-- the original built-in sub-commands are already handled by default.
121
+ cmds = (self.get_finalized_command(c) for c in missing_cmds)
122
+ files = (c.get_source_files() for c in cmds if hasattr(c, "get_source_files"))
123
+ self.filelist.extend(chain.from_iterable(files))
124
+
125
+ def _safe_data_files(self, build_py):
126
+ """
127
+ Since the ``sdist`` class is also used to compute the MANIFEST
128
+ (via :obj:`setuptools.command.egg_info.manifest_maker`),
129
+ there might be recursion problems when trying to obtain the list of
130
+ data_files and ``include_package_data=True`` (which in turn depends on
131
+ the files included in the MANIFEST).
132
+
133
+ To avoid that, ``manifest_maker`` should be able to overwrite this
134
+ method and avoid recursive attempts to build/analyze the MANIFEST.
135
+ """
136
+ return build_py.data_files
137
+
138
+ def _add_data_files(self, data_files):
139
+ """
140
+ Add data files as found in build_py.data_files.
141
+ """
142
+ self.filelist.extend(
143
+ os.path.join(src_dir, name)
144
+ for _, src_dir, _, filenames in data_files
145
+ for name in filenames
146
+ )
147
+
148
+ def _add_defaults_data_files(self):
149
+ try:
150
+ super()._add_defaults_data_files()
151
+ except TypeError:
152
+ log.warn("data_files contains unexpected objects")
153
+
154
+ def check_readme(self):
155
+ for f in self.READMES:
156
+ if os.path.exists(f):
157
+ return
158
+ else:
159
+ self.warn(
160
+ "standard file not found: should have one of " + ', '.join(self.READMES)
161
+ )
162
+
163
+ def make_release_tree(self, base_dir, files):
164
+ orig.sdist.make_release_tree(self, base_dir, files)
165
+
166
+ # Save any egg_info command line options used to create this sdist
167
+ dest = os.path.join(base_dir, 'setup.cfg')
168
+ if hasattr(os, 'link') and os.path.exists(dest):
169
+ # unlink and re-copy, since it might be hard-linked, and
170
+ # we don't want to change the source version
171
+ os.unlink(dest)
172
+ self.copy_file('setup.cfg', dest)
173
+
174
+ self.get_finalized_command('egg_info').save_version_info(dest)
175
+
176
+ def _manifest_is_not_generated(self):
177
+ # check for special comment used in 2.7.1 and higher
178
+ if not os.path.isfile(self.manifest):
179
+ return False
180
+
181
+ with open(self.manifest, 'rb') as fp:
182
+ first_line = fp.readline()
183
+ return first_line != b'# file GENERATED by distutils, do NOT edit\n'
184
+
185
+ def read_manifest(self):
186
+ """Read the manifest file (named by 'self.manifest') and use it to
187
+ fill in 'self.filelist', the list of files to include in the source
188
+ distribution.
189
+ """
190
+ log.info("reading manifest file '%s'", self.manifest)
191
+ manifest = open(self.manifest, 'rb')
192
+ for line in manifest:
193
+ # The manifest must contain UTF-8. See #303.
194
+ try:
195
+ line = line.decode('UTF-8')
196
+ except UnicodeDecodeError:
197
+ log.warn("%r not UTF-8 decodable -- skipping" % line)
198
+ continue
199
+ # ignore comments and blank lines
200
+ line = line.strip()
201
+ if line.startswith('#') or not line:
202
+ continue
203
+ self.filelist.append(line)
204
+ manifest.close()
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/setopt.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from distutils.util import convert_path
2
+ from distutils import log
3
+ from distutils.errors import DistutilsOptionError
4
+ import distutils
5
+ import os
6
+ import configparser
7
+
8
+ from .. import Command
9
+ from ..unicode_utils import _cfg_read_utf8_with_fallback
10
+
11
+ __all__ = ['config_file', 'edit_config', 'option_base', 'setopt']
12
+
13
+
14
+ def config_file(kind="local"):
15
+ """Get the filename of the distutils, local, global, or per-user config
16
+
17
+ `kind` must be one of "local", "global", or "user"
18
+ """
19
+ if kind == 'local':
20
+ return 'setup.cfg'
21
+ if kind == 'global':
22
+ return os.path.join(os.path.dirname(distutils.__file__), 'distutils.cfg')
23
+ if kind == 'user':
24
+ dot = os.name == 'posix' and '.' or ''
25
+ return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot))
26
+ raise ValueError("config_file() type must be 'local', 'global', or 'user'", kind)
27
+
28
+
29
+ def edit_config(filename, settings, dry_run=False):
30
+ """Edit a configuration file to include `settings`
31
+
32
+ `settings` is a dictionary of dictionaries or ``None`` values, keyed by
33
+ command/section name. A ``None`` value means to delete the entire section,
34
+ while a dictionary lists settings to be changed or deleted in that section.
35
+ A setting of ``None`` means to delete that setting.
36
+ """
37
+ log.debug("Reading configuration from %s", filename)
38
+ opts = configparser.RawConfigParser()
39
+ opts.optionxform = lambda x: x
40
+ _cfg_read_utf8_with_fallback(opts, filename)
41
+
42
+ for section, options in settings.items():
43
+ if options is None:
44
+ log.info("Deleting section [%s] from %s", section, filename)
45
+ opts.remove_section(section)
46
+ else:
47
+ if not opts.has_section(section):
48
+ log.debug("Adding new section [%s] to %s", section, filename)
49
+ opts.add_section(section)
50
+ for option, value in options.items():
51
+ if value is None:
52
+ log.debug("Deleting %s.%s from %s", section, option, filename)
53
+ opts.remove_option(section, option)
54
+ if not opts.options(section):
55
+ log.info(
56
+ "Deleting empty [%s] section from %s", section, filename
57
+ )
58
+ opts.remove_section(section)
59
+ else:
60
+ log.debug(
61
+ "Setting %s.%s to %r in %s", section, option, value, filename
62
+ )
63
+ opts.set(section, option, value)
64
+
65
+ log.info("Writing %s", filename)
66
+ if not dry_run:
67
+ with open(filename, 'w', encoding="utf-8") as f:
68
+ opts.write(f)
69
+
70
+
71
+ class option_base(Command):
72
+ """Abstract base class for commands that mess with config files"""
73
+
74
+ user_options = [
75
+ ('global-config', 'g', "save options to the site-wide distutils.cfg file"),
76
+ ('user-config', 'u', "save options to the current user's pydistutils.cfg file"),
77
+ ('filename=', 'f', "configuration file to use (default=setup.cfg)"),
78
+ ]
79
+
80
+ boolean_options = [
81
+ 'global-config',
82
+ 'user-config',
83
+ ]
84
+
85
+ def initialize_options(self):
86
+ self.global_config = None
87
+ self.user_config = None
88
+ self.filename = None
89
+
90
+ def finalize_options(self):
91
+ filenames = []
92
+ if self.global_config:
93
+ filenames.append(config_file('global'))
94
+ if self.user_config:
95
+ filenames.append(config_file('user'))
96
+ if self.filename is not None:
97
+ filenames.append(self.filename)
98
+ if not filenames:
99
+ filenames.append(config_file('local'))
100
+ if len(filenames) > 1:
101
+ raise DistutilsOptionError(
102
+ "Must specify only one configuration file option", filenames
103
+ )
104
+ (self.filename,) = filenames
105
+
106
+
107
+ class setopt(option_base):
108
+ """Save command-line options to a file"""
109
+
110
+ description = "set an option in setup.cfg or another config file"
111
+
112
+ user_options = [
113
+ ('command=', 'c', 'command to set an option for'),
114
+ ('option=', 'o', 'option to set'),
115
+ ('set-value=', 's', 'value of the option'),
116
+ ('remove', 'r', 'remove (unset) the value'),
117
+ ] + option_base.user_options
118
+
119
+ boolean_options = option_base.boolean_options + ['remove']
120
+
121
+ def initialize_options(self):
122
+ option_base.initialize_options(self)
123
+ self.command = None
124
+ self.option = None
125
+ self.set_value = None
126
+ self.remove = None
127
+
128
+ def finalize_options(self):
129
+ option_base.finalize_options(self)
130
+ if self.command is None or self.option is None:
131
+ raise DistutilsOptionError("Must specify --command *and* --option")
132
+ if self.set_value is None and not self.remove:
133
+ raise DistutilsOptionError("Must specify --set-value or --remove")
134
+
135
+ def run(self):
136
+ edit_config(
137
+ self.filename,
138
+ {self.command: {self.option.replace('-', '_'): self.set_value}},
139
+ self.dry_run,
140
+ )
URSA/.venv_ursa/lib/python3.12/site-packages/setuptools/command/test.py ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import operator
3
+ import sys
4
+ import contextlib
5
+ import itertools
6
+ import unittest
7
+ from distutils.errors import DistutilsError, DistutilsOptionError
8
+ from distutils import log
9
+ from unittest import TestLoader
10
+
11
+ from pkg_resources import (
12
+ resource_listdir,
13
+ resource_exists,
14
+ normalize_path,
15
+ working_set,
16
+ evaluate_marker,
17
+ add_activation_listener,
18
+ require,
19
+ )
20
+ from .._importlib import metadata
21
+ from setuptools import Command
22
+ from setuptools.extern.more_itertools import unique_everseen
23
+ from setuptools.extern.jaraco.functools import pass_none
24
+
25
+
26
+ class ScanningLoader(TestLoader):
27
+ def __init__(self):
28
+ TestLoader.__init__(self)
29
+ self._visited = set()
30
+
31
+ def loadTestsFromModule(self, module, pattern=None):
32
+ """Return a suite of all tests cases contained in the given module
33
+
34
+ If the module is a package, load tests from all the modules in it.
35
+ If the module has an ``additional_tests`` function, call it and add
36
+ the return value to the tests.
37
+ """
38
+ if module in self._visited:
39
+ return None
40
+ self._visited.add(module)
41
+
42
+ tests = []
43
+ tests.append(TestLoader.loadTestsFromModule(self, module))
44
+
45
+ if hasattr(module, "additional_tests"):
46
+ tests.append(module.additional_tests())
47
+
48
+ if hasattr(module, '__path__'):
49
+ for file in resource_listdir(module.__name__, ''):
50
+ if file.endswith('.py') and file != '__init__.py':
51
+ submodule = module.__name__ + '.' + file[:-3]
52
+ else:
53
+ if resource_exists(module.__name__, file + '/__init__.py'):
54
+ submodule = module.__name__ + '.' + file
55
+ else:
56
+ continue
57
+ tests.append(self.loadTestsFromName(submodule))
58
+
59
+ if len(tests) != 1:
60
+ return self.suiteClass(tests)
61
+ else:
62
+ return tests[0] # don't create a nested suite for only one return
63
+
64
+
65
+ # adapted from jaraco.classes.properties:NonDataProperty
66
+ class NonDataProperty:
67
+ def __init__(self, fget):
68
+ self.fget = fget
69
+
70
+ def __get__(self, obj, objtype=None):
71
+ if obj is None:
72
+ return self
73
+ return self.fget(obj)
74
+
75
+
76
+ class test(Command):
77
+ """Command to run unit tests after in-place build"""
78
+
79
+ description = "run unit tests after in-place build (deprecated)"
80
+
81
+ user_options = [
82
+ ('test-module=', 'm', "Run 'test_suite' in specified module"),
83
+ (
84
+ 'test-suite=',
85
+ 's',
86
+ "Run single test, case or suite (e.g. 'module.test_suite')",
87
+ ),
88
+ ('test-runner=', 'r', "Test runner to use"),
89
+ ]
90
+
91
+ def initialize_options(self):
92
+ self.test_suite = None
93
+ self.test_module = None
94
+ self.test_loader = None
95
+ self.test_runner = None
96
+
97
+ def finalize_options(self):
98
+ if self.test_suite and self.test_module:
99
+ msg = "You may specify a module or a suite, but not both"
100
+ raise DistutilsOptionError(msg)
101
+
102
+ if self.test_suite is None:
103
+ if self.test_module is None:
104
+ self.test_suite = self.distribution.test_suite
105
+ else:
106
+ self.test_suite = self.test_module + ".test_suite"
107
+
108
+ if self.test_loader is None:
109
+ self.test_loader = getattr(self.distribution, 'test_loader', None)
110
+ if self.test_loader is None:
111
+ self.test_loader = "setuptools.command.test:ScanningLoader"
112
+ if self.test_runner is None:
113
+ self.test_runner = getattr(self.distribution, 'test_runner', None)
114
+
115
+ @NonDataProperty
116
+ def test_args(self):
117
+ return list(self._test_args())
118
+
119
+ def _test_args(self):
120
+ if not self.test_suite:
121
+ yield 'discover'
122
+ if self.verbose:
123
+ yield '--verbose'
124
+ if self.test_suite:
125
+ yield self.test_suite
126
+
127
+ def with_project_on_sys_path(self, func):
128
+ """
129
+ Backward compatibility for project_on_sys_path context.
130
+ """
131
+ with self.project_on_sys_path():
132
+ func()
133
+
134
+ @contextlib.contextmanager
135
+ def project_on_sys_path(self, include_dists=()):
136
+ self.run_command('egg_info')
137
+
138
+ # Build extensions in-place
139
+ self.reinitialize_command('build_ext', inplace=True)
140
+ self.run_command('build_ext')
141
+
142
+ ei_cmd = self.get_finalized_command("egg_info")
143
+
144
+ old_path = sys.path[:]
145
+ old_modules = sys.modules.copy()
146
+
147
+ try:
148
+ project_path = normalize_path(ei_cmd.egg_base)
149
+ sys.path.insert(0, project_path)
150
+ working_set.__init__()
151
+ add_activation_listener(lambda dist: dist.activate())
152
+ require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version))
153
+ with self.paths_on_pythonpath([project_path]):
154
+ yield
155
+ finally:
156
+ sys.path[:] = old_path
157
+ sys.modules.clear()
158
+ sys.modules.update(old_modules)
159
+ working_set.__init__()
160
+
161
+ @staticmethod
162
+ @contextlib.contextmanager
163
+ def paths_on_pythonpath(paths):
164
+ """
165
+ Add the indicated paths to the head of the PYTHONPATH environment
166
+ variable so that subprocesses will also see the packages at
167
+ these paths.
168
+
169
+ Do this in a context that restores the value on exit.
170
+ """
171
+ nothing = object()
172
+ orig_pythonpath = os.environ.get('PYTHONPATH', nothing)
173
+ current_pythonpath = os.environ.get('PYTHONPATH', '')
174
+ try:
175
+ prefix = os.pathsep.join(unique_everseen(paths))
176
+ to_join = filter(None, [prefix, current_pythonpath])
177
+ new_path = os.pathsep.join(to_join)
178
+ if new_path:
179
+ os.environ['PYTHONPATH'] = new_path
180
+ yield
181
+ finally:
182
+ if orig_pythonpath is nothing:
183
+ os.environ.pop('PYTHONPATH', None)
184
+ else:
185
+ os.environ['PYTHONPATH'] = orig_pythonpath
186
+
187
+ @staticmethod
188
+ def install_dists(dist):
189
+ """
190
+ Install the requirements indicated by self.distribution and
191
+ return an iterable of the dists that were built.
192
+ """
193
+ ir_d = dist.fetch_build_eggs(dist.install_requires)
194
+ tr_d = dist.fetch_build_eggs(dist.tests_require or [])
195
+ er_d = dist.fetch_build_eggs(
196
+ v
197
+ for k, v in dist.extras_require.items()
198
+ if k.startswith(':') and evaluate_marker(k[1:])
199
+ )
200
+ return itertools.chain(ir_d, tr_d, er_d)
201
+
202
+ def run(self):
203
+ self.announce(
204
+ "WARNING: Testing via this command is deprecated and will be "
205
+ "removed in a future version. Users looking for a generic test "
206
+ "entry point independent of test runner are encouraged to use "
207
+ "tox.",
208
+ log.WARN,
209
+ )
210
+
211
+ installed_dists = self.install_dists(self.distribution)
212
+
213
+ cmd = ' '.join(self._argv)
214
+ if self.dry_run:
215
+ self.announce('skipping "%s" (dry run)' % cmd)
216
+ return
217
+
218
+ self.announce('running "%s"' % cmd)
219
+
220
+ paths = map(operator.attrgetter('location'), installed_dists)
221
+ with self.paths_on_pythonpath(paths):
222
+ with self.project_on_sys_path():
223
+ self.run_tests()
224
+
225
+ def run_tests(self):
226
+ test = unittest.main(
227
+ None,
228
+ None,
229
+ self._argv,
230
+ testLoader=self._resolve_as_ep(self.test_loader),
231
+ testRunner=self._resolve_as_ep(self.test_runner),
232
+ exit=False,
233
+ )
234
+ if not test.result.wasSuccessful():
235
+ msg = 'Test failed: %s' % test.result
236
+ self.announce(msg, log.ERROR)
237
+ raise DistutilsError(msg)
238
+
239
+ @property
240
+ def _argv(self):
241
+ return ['unittest'] + self.test_args
242
+
243
+ @staticmethod
244
+ @pass_none
245
+ def _resolve_as_ep(val):
246
+ """
247
+ Load the indicated attribute value, called, as a as if it were
248
+ specified as an entry point.
249
+ """
250
+ return metadata.EntryPoint(value=val, name=None, group=None).load()()
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/__autotune_main__.cpython-312.pyc ADDED
Binary file (1.87 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (15 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/aoti_eager.cpython-312.pyc ADDED
Binary file (13.9 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/autotune_process.cpython-312.pyc ADDED
Binary file (47.7 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/await_utils.cpython-312.pyc ADDED
Binary file (8.25 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/bounds.cpython-312.pyc ADDED
Binary file (14.3 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/cache.cpython-312.pyc ADDED
Binary file (17.3 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/comm_analysis.cpython-312.pyc ADDED
Binary file (18.8 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/comm_lowering.cpython-312.pyc ADDED
Binary file (16.4 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/comms.cpython-312.pyc ADDED
Binary file (92.5 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/comms_debug.cpython-312.pyc ADDED
Binary file (4.66 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/compile_fx_subproc.cpython-312.pyc ADDED
Binary file (2.99 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/config_comms.cpython-312.pyc ADDED
Binary file (2.17 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/constant_folding.cpython-312.pyc ADDED
Binary file (21.3 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/cpp_builder.cpython-312.pyc ADDED
Binary file (97.3 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/cpu_vec_isa.cpython-312.pyc ADDED
Binary file (21.8 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/custom_graph_pass.cpython-312.pyc ADDED
Binary file (7.97 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/debug.cpython-312.pyc ADDED
Binary file (58.9 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/decomposition.cpython-312.pyc ADDED
Binary file (59.2 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/dependencies.cpython-312.pyc ADDED
Binary file (46.7 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/distributed_autotune.cpython-312.pyc ADDED
Binary file (15.5 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/exc.cpython-312.pyc ADDED
Binary file (8.89 kB). View file
 
URSA/.venv_ursa/lib/python3.12/site-packages/torch/_inductor/__pycache__/extern_node_serializer.cpython-312.pyc ADDED
Binary file (1.4 kB). View file