omdev 0.0.0.dev7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. omdev/__about__.py +35 -0
  2. omdev/__init__.py +0 -0
  3. omdev/amalg/__init__.py +0 -0
  4. omdev/amalg/__main__.py +4 -0
  5. omdev/amalg/amalg.py +513 -0
  6. omdev/classdot.py +61 -0
  7. omdev/cmake.py +164 -0
  8. omdev/exts/__init__.py +0 -0
  9. omdev/exts/_distutils/__init__.py +10 -0
  10. omdev/exts/_distutils/build_ext.py +367 -0
  11. omdev/exts/_distutils/compilers/__init__.py +3 -0
  12. omdev/exts/_distutils/compilers/ccompiler.py +1032 -0
  13. omdev/exts/_distutils/compilers/options.py +80 -0
  14. omdev/exts/_distutils/compilers/unixccompiler.py +385 -0
  15. omdev/exts/_distutils/dir_util.py +76 -0
  16. omdev/exts/_distutils/errors.py +62 -0
  17. omdev/exts/_distutils/extension.py +107 -0
  18. omdev/exts/_distutils/file_util.py +216 -0
  19. omdev/exts/_distutils/modified.py +47 -0
  20. omdev/exts/_distutils/spawn.py +103 -0
  21. omdev/exts/_distutils/sysconfig.py +349 -0
  22. omdev/exts/_distutils/util.py +201 -0
  23. omdev/exts/_distutils/version.py +308 -0
  24. omdev/exts/build.py +43 -0
  25. omdev/exts/cmake.py +195 -0
  26. omdev/exts/importhook.py +88 -0
  27. omdev/exts/scan.py +74 -0
  28. omdev/interp/__init__.py +1 -0
  29. omdev/interp/__main__.py +4 -0
  30. omdev/interp/cli.py +63 -0
  31. omdev/interp/inspect.py +105 -0
  32. omdev/interp/providers.py +67 -0
  33. omdev/interp/pyenv.py +353 -0
  34. omdev/interp/resolvers.py +76 -0
  35. omdev/interp/standalone.py +187 -0
  36. omdev/interp/system.py +125 -0
  37. omdev/interp/types.py +92 -0
  38. omdev/mypy/__init__.py +0 -0
  39. omdev/mypy/debug.py +86 -0
  40. omdev/pyproject/__init__.py +1 -0
  41. omdev/pyproject/__main__.py +4 -0
  42. omdev/pyproject/cli.py +319 -0
  43. omdev/pyproject/configs.py +97 -0
  44. omdev/pyproject/ext.py +107 -0
  45. omdev/pyproject/pkg.py +196 -0
  46. omdev/scripts/__init__.py +0 -0
  47. omdev/scripts/execrss.py +19 -0
  48. omdev/scripts/findimports.py +62 -0
  49. omdev/scripts/findmagic.py +70 -0
  50. omdev/scripts/interp.py +2118 -0
  51. omdev/scripts/pyproject.py +3584 -0
  52. omdev/scripts/traceimport.py +502 -0
  53. omdev/tokens.py +42 -0
  54. omdev/toml/__init__.py +1 -0
  55. omdev/toml/parser.py +823 -0
  56. omdev/toml/writer.py +104 -0
  57. omdev/tools/__init__.py +0 -0
  58. omdev/tools/dockertools.py +81 -0
  59. omdev/tools/sqlrepl.py +193 -0
  60. omdev/versioning/__init__.py +1 -0
  61. omdev/versioning/specifiers.py +531 -0
  62. omdev/versioning/versions.py +416 -0
  63. omdev-0.0.0.dev7.dist-info/LICENSE +21 -0
  64. omdev-0.0.0.dev7.dist-info/METADATA +24 -0
  65. omdev-0.0.0.dev7.dist-info/RECORD +67 -0
  66. omdev-0.0.0.dev7.dist-info/WHEEL +5 -0
  67. omdev-0.0.0.dev7.dist-info/top_level.txt +1 -0
@@ -0,0 +1,76 @@
1
+ # ruff: noqa: UP006
2
+ import abc
3
+ import collections
4
+ import typing as ta
5
+
6
+ from omlish.lite.reflect import deep_subclasses
7
+
8
+ from .providers import InterpProvider
9
+ from .providers import RunningInterpProvider
10
+ from .pyenv import PyenvInterpProvider
11
+ from .system import SystemInterpProvider
12
+ from .types import Interp
13
+ from .types import InterpSpecifier
14
+
15
+
16
+ INTERP_PROVIDER_TYPES_BY_NAME: ta.Mapping[str, ta.Type[InterpProvider]] = {
17
+ cls.name: cls for cls in deep_subclasses(InterpProvider) if abc.ABC not in cls.__bases__ # type: ignore
18
+ }
19
+
20
+
21
+ class InterpResolver:
22
+ def __init__(
23
+ self,
24
+ providers: ta.Sequence[ta.Tuple[str, InterpProvider]],
25
+ ) -> None:
26
+ super().__init__()
27
+ self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers)
28
+
29
+ def resolve(self, spec: InterpSpecifier) -> Interp:
30
+ lst = [
31
+ (i, si)
32
+ for i, p in enumerate(self._providers.values())
33
+ for si in p.get_installed_versions(spec)
34
+ if spec.contains(si)
35
+ ]
36
+ best = sorted(lst, key=lambda t: (-t[0], t[1]))[-1]
37
+ bi, bv = best
38
+ bp = list(self._providers.values())[bi]
39
+ return bp.get_installed_version(bv)
40
+
41
+ def list(self, spec: InterpSpecifier) -> None:
42
+ print('installed:')
43
+ for n, p in self._providers.items():
44
+ lst = [
45
+ si
46
+ for si in p.get_installed_versions(spec)
47
+ if spec.contains(si)
48
+ ]
49
+ if lst:
50
+ print(f' {n}')
51
+ for si in lst:
52
+ print(f' {si}')
53
+
54
+ print()
55
+
56
+ print('installable:')
57
+ for n, p in self._providers.items():
58
+ lst = [
59
+ si
60
+ for si in p.get_installable_versions(spec)
61
+ if spec.contains(si)
62
+ ]
63
+ if lst:
64
+ print(f' {n}')
65
+ for si in lst:
66
+ print(f' {si}')
67
+
68
+
69
+ DEFAULT_INTERP_RESOLVER = InterpResolver([(p.name, p) for p in [
70
+ # pyenv is preferred to system interpreters as it tends to have more support for things like tkinter
71
+ PyenvInterpProvider(),
72
+
73
+ RunningInterpProvider(),
74
+
75
+ SystemInterpProvider(),
76
+ ]])
@@ -0,0 +1,187 @@
1
+ """
2
+ TODO:
3
+ - ~/.cache/omlish/interp/standalone/...
4
+ - remove fallback
5
+ """
6
+ # MIT License
7
+ #
8
+ # Copyright (c) 2023 Tushar Sadhwani
9
+ #
10
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
11
+ # documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
12
+ # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
16
+ # Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
19
+ # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20
+ # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
21
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ # https://github.com/tusharsadhwani/yen/blob/8d1bb0c1232c7b0159caefb1bf3a5348b93f7b43/src/yen/github.py
23
+ # ruff: noqa: UP006 UP007
24
+ import json
25
+ import os.path
26
+ import platform
27
+ import re
28
+ import typing
29
+ import typing as ta
30
+ import urllib.error
31
+ import urllib.parse
32
+ import urllib.request
33
+
34
+ from omlish.lite.cached import cached_nullary
35
+ from omlish.lite.check import check_not_none
36
+ from omlish.lite.logs import log
37
+
38
+
39
+ class StandalonePythons:
40
+ LAST_TAG_FOR_I686_LINUX = '118809599' # tag name: "20230826"
41
+
42
+ MACHINE_SUFFIX: ta.Mapping[str, ta.Mapping[str, ta.Any]] = {
43
+ 'Darwin': {
44
+ 'arm64': ['aarch64-apple-darwin-install_only.tar.gz'],
45
+ 'x86_64': ['x86_64-apple-darwin-install_only.tar.gz'],
46
+ },
47
+ 'Linux': {
48
+ 'aarch64': {
49
+ 'glibc': ['aarch64-unknown-linux-gnu-install_only.tar.gz'],
50
+ # musl doesn't exist
51
+ },
52
+ 'x86_64': {
53
+ 'glibc': [
54
+ 'x86_64_v3-unknown-linux-gnu-install_only.tar.gz',
55
+ 'x86_64-unknown-linux-gnu-install_only.tar.gz',
56
+ ],
57
+ 'musl': ['x86_64_v3-unknown-linux-musl-install_only.tar.gz'],
58
+ },
59
+ 'i686': {
60
+ 'glibc': ['i686-unknown-linux-gnu-install_only.tar.gz'],
61
+ # musl doesn't exist
62
+ },
63
+ },
64
+ 'Windows': {
65
+ 'AMD64': ['x86_64-pc-windows-msvc-shared-install_only.tar.gz'],
66
+ 'i686': ['i686-pc-windows-msvc-install_only.tar.gz'],
67
+ },
68
+ }
69
+
70
+ GITHUB_API_RELEASES_URL = 'https://api.github.com/repos/indygreg/python-build-standalone/releases/'
71
+
72
+ PYTHON_VERSION_REGEX = re.compile(r'cpython-(\d+\.\d+\.\d+)')
73
+
74
+ class GitHubReleaseData(ta.TypedDict):
75
+ id: int
76
+ html_url: str
77
+ assets: ta.List['StandalonePythons.GitHubAsset']
78
+
79
+ class GitHubAsset(ta.TypedDict):
80
+ browser_download_url: str
81
+
82
+ def trim_github_release_data(self, release_data: ta.Dict[str, ta.Any]) -> GitHubReleaseData:
83
+ return {
84
+ 'id': release_data['id'],
85
+ 'html_url': release_data['html_url'],
86
+ 'assets': [
87
+ {'browser_download_url': asset['browser_download_url']}
88
+ for asset in release_data['assets']
89
+ ],
90
+ }
91
+
92
+ def fallback_release_data(self) -> GitHubReleaseData:
93
+ """Returns the fallback release data, for when GitHub API gives an error."""
94
+ log.warning('GitHub unreachable. Using fallback release data.')
95
+ data_file = os.path.join(os.path.dirname(__file__), 'fallback_release_data.json')
96
+ with open(data_file) as data:
97
+ return typing.cast(StandalonePythons.GitHubReleaseData, json.load(data))
98
+
99
+ class NotAvailableError(Exception):
100
+ """Raised when the asked Python version is not available."""
101
+
102
+ def get_latest_python_releases(self, is_linux_i686: bool) -> GitHubReleaseData:
103
+ """Returns the list of python download links from the latest github release."""
104
+ # They stopped shipping for 32 bit linux since after the 20230826 tag
105
+ if is_linux_i686:
106
+ data_file = os.path.join(os.path.dirname(__file__), 'linux_i686_release.json')
107
+ with open(data_file) as data:
108
+ return typing.cast(StandalonePythons.GitHubReleaseData, json.load(data))
109
+
110
+ latest_release_url = urllib.parse.urljoin(self.GITHUB_API_RELEASES_URL, 'latest')
111
+ try:
112
+ with urllib.request.urlopen(latest_release_url) as response: # noqa
113
+ release_data = typing.cast(StandalonePythons.GitHubReleaseData, json.load(response))
114
+
115
+ except urllib.error.URLError:
116
+ release_data = self.fallback_release_data()
117
+
118
+ return release_data
119
+
120
+ @cached_nullary
121
+ def list_pythons(self) -> ta.Mapping[str, str]:
122
+ """Returns available python versions for your machine and their download links."""
123
+ system, machine = platform.system(), platform.machine()
124
+ download_link_suffixes = self.MACHINE_SUFFIX[system][machine]
125
+ # linux suffixes are nested under glibc or musl builds
126
+ if system == 'Linux':
127
+ # fallback to musl if libc version is not found
128
+ libc_version = platform.libc_ver()[0] or 'musl'
129
+ download_link_suffixes = download_link_suffixes[libc_version]
130
+
131
+ is_linux_i686 = system == 'Linux' and machine == 'i686'
132
+ releases = self.get_latest_python_releases(is_linux_i686)
133
+ python_releases = [asset['browser_download_url'] for asset in releases['assets']]
134
+
135
+ available_python_links = [
136
+ link
137
+ # Suffixes are in order of preference.
138
+ for download_link_suffix in download_link_suffixes
139
+ for link in python_releases
140
+ if link.endswith(download_link_suffix)
141
+ ]
142
+
143
+ python_versions: ta.Dict[str, str] = {}
144
+ for link in available_python_links:
145
+ match = self.PYTHON_VERSION_REGEX.search(link)
146
+ python_version = check_not_none(match)[1]
147
+ # Don't override already found versions, as they are in order of preference
148
+ if python_version in python_versions:
149
+ continue
150
+
151
+ python_versions[python_version] = link
152
+
153
+ sorted_python_versions = {
154
+ version: python_versions[version]
155
+ for version in sorted(
156
+ python_versions,
157
+ # sort by semver
158
+ key=lambda version: [int(k) for k in version.split('.')],
159
+ reverse=True,
160
+ )
161
+ }
162
+ return sorted_python_versions
163
+
164
+ def _parse_python_version(self, version: str) -> ta.Tuple[int, ...]:
165
+ return tuple(int(k) for k in version.split('.'))
166
+
167
+ def resolve_python_version(self, requested_version: ta.Optional[str]) -> ta.Tuple[str, str]:
168
+ pythons = self.list_pythons()
169
+
170
+ if requested_version is None:
171
+ sorted_pythons = sorted(
172
+ pythons.items(),
173
+ key=lambda version_link: self._parse_python_version(version_link[0]),
174
+ reverse=True,
175
+ )
176
+ latest_version, download_link = sorted_pythons[0]
177
+ return latest_version, download_link
178
+
179
+ for version, version_download_link in pythons.items():
180
+ if version.startswith(requested_version):
181
+ python_version = version
182
+ download_link = version_download_link
183
+ break
184
+ else:
185
+ raise StandalonePythons.NotAvailableError
186
+
187
+ return python_version, download_link
omdev/interp/system.py ADDED
@@ -0,0 +1,125 @@
1
+ """
2
+ TODO:
3
+ - python, python3, python3.12, ...
4
+ - check if path py's are venvs: sys.prefix != sys.base_prefix
5
+ """
6
+ # ruff: noqa: UP006 UP007
7
+ import dataclasses as dc
8
+ import os
9
+ import re
10
+ import typing as ta
11
+
12
+ from omlish.lite.cached import cached_nullary
13
+ from omlish.lite.logs import log
14
+
15
+ from ..versioning.versions import InvalidVersion
16
+ from .inspect import INTERP_INSPECTOR
17
+ from .inspect import InterpInspector
18
+ from .providers import InterpProvider
19
+ from .types import Interp
20
+ from .types import InterpSpecifier
21
+ from .types import InterpVersion
22
+
23
+
24
+ ##
25
+
26
+
27
+ @dc.dataclass(frozen=True)
28
+ class SystemInterpProvider(InterpProvider):
29
+ cmd: str = 'python3'
30
+ path: ta.Optional[str] = None
31
+
32
+ inspect: bool = False
33
+ inspector: InterpInspector = INTERP_INSPECTOR
34
+
35
+ #
36
+
37
+ @staticmethod
38
+ def _re_which(
39
+ pat: re.Pattern,
40
+ *,
41
+ mode: int = os.F_OK | os.X_OK,
42
+ path: ta.Optional[str] = None,
43
+ ) -> ta.List[str]:
44
+ if path is None:
45
+ path = os.environ.get('PATH', None)
46
+ if path is None:
47
+ try:
48
+ path = os.confstr('CS_PATH')
49
+ except (AttributeError, ValueError):
50
+ path = os.defpath
51
+
52
+ if not path:
53
+ return []
54
+
55
+ path = os.fsdecode(path)
56
+ pathlst = path.split(os.pathsep)
57
+
58
+ def _access_check(fn: str, mode: int) -> bool:
59
+ return os.path.exists(fn) and os.access(fn, mode)
60
+
61
+ out = []
62
+ seen = set()
63
+ for d in pathlst:
64
+ normdir = os.path.normcase(d)
65
+ if normdir not in seen:
66
+ seen.add(normdir)
67
+ if not _access_check(normdir, mode):
68
+ continue
69
+ for thefile in os.listdir(d):
70
+ name = os.path.join(d, thefile)
71
+ if not (
72
+ os.path.isfile(name) and
73
+ pat.fullmatch(thefile) and
74
+ _access_check(name, mode)
75
+ ):
76
+ continue
77
+ out.append(name)
78
+
79
+ return out
80
+
81
+ @cached_nullary
82
+ def exes(self) -> ta.List[str]:
83
+ return self._re_which(
84
+ re.compile(r'python3(\.\d+)?'),
85
+ path=self.path,
86
+ )
87
+
88
+ #
89
+
90
+ def get_exe_version(self, exe: str) -> ta.Optional[InterpVersion]:
91
+ if not self.inspect:
92
+ s = os.path.basename(exe)
93
+ if s.startswith('python'):
94
+ s = s[len('python'):]
95
+ if '.' in s:
96
+ try:
97
+ return InterpVersion.parse(s)
98
+ except InvalidVersion:
99
+ pass
100
+ ii = self.inspector.inspect(exe)
101
+ return ii.iv if ii is not None else None
102
+
103
+ def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
104
+ lst = []
105
+ for e in self.exes():
106
+ if (ev := self.get_exe_version(e)) is None:
107
+ log.debug('Invalid system version: %s', e)
108
+ continue
109
+ lst.append((e, ev))
110
+ return lst
111
+
112
+ #
113
+
114
+ def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
115
+ return [ev for e, ev in self.exe_versions()]
116
+
117
+ def get_installed_version(self, version: InterpVersion) -> Interp:
118
+ for e, ev in self.exe_versions():
119
+ if ev != version:
120
+ continue
121
+ return Interp(
122
+ exe=e,
123
+ version=ev,
124
+ )
125
+ raise KeyError(version)
omdev/interp/types.py ADDED
@@ -0,0 +1,92 @@
1
+ # ruff: noqa: UP006
2
+ import collections
3
+ import dataclasses as dc
4
+ import typing as ta
5
+
6
+ from ..versioning.specifiers import Specifier
7
+ from ..versioning.versions import InvalidVersion
8
+ from ..versioning.versions import Version
9
+
10
+
11
+ # See https://peps.python.org/pep-3149/
12
+ INTERP_OPT_GLYPHS_BY_ATTR: ta.Mapping[str, str] = collections.OrderedDict([
13
+ ('debug', 'd'),
14
+ ('threaded', 't'),
15
+ ])
16
+
17
+ INTERP_OPT_ATTRS_BY_GLYPH: ta.Mapping[str, str] = collections.OrderedDict(
18
+ (g, a) for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items()
19
+ )
20
+
21
+
22
+ @dc.dataclass(frozen=True)
23
+ class InterpOpts:
24
+ threaded: bool = False
25
+ debug: bool = False
26
+
27
+ def __str__(self) -> str:
28
+ return ''.join(g for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items() if getattr(self, a))
29
+
30
+ @classmethod
31
+ def parse(cls, s: str) -> 'InterpOpts':
32
+ return cls(**{INTERP_OPT_ATTRS_BY_GLYPH[g]: True for g in s})
33
+
34
+ @classmethod
35
+ def parse_suffix(cls, s: str) -> ta.Tuple[str, 'InterpOpts']:
36
+ kw = {}
37
+ while s and (a := INTERP_OPT_ATTRS_BY_GLYPH.get(s[-1])):
38
+ s, kw[a] = s[:-1], True
39
+ return s, cls(**kw)
40
+
41
+
42
+ @dc.dataclass(frozen=True)
43
+ class InterpVersion:
44
+ version: Version
45
+ opts: InterpOpts
46
+
47
+ def __str__(self) -> str:
48
+ return str(self.version) + str(self.opts)
49
+
50
+ @classmethod
51
+ def parse(cls, s: str) -> 'InterpVersion':
52
+ s, o = InterpOpts.parse_suffix(s)
53
+ v = Version(s)
54
+ return cls(
55
+ version=v,
56
+ opts=o,
57
+ )
58
+
59
+ @classmethod
60
+ def try_parse(cls, s: str) -> ta.Optional['InterpVersion']:
61
+ try:
62
+ return cls.parse(s)
63
+ except (KeyError, InvalidVersion):
64
+ return None
65
+
66
+
67
+ @dc.dataclass(frozen=True)
68
+ class InterpSpecifier:
69
+ specifier: Specifier
70
+ opts: InterpOpts
71
+
72
+ def __str__(self) -> str:
73
+ return str(self.specifier) + str(self.opts)
74
+
75
+ @classmethod
76
+ def parse(cls, s: str) -> 'InterpSpecifier':
77
+ s, o = InterpOpts.parse_suffix(s)
78
+ if not any(s.startswith(o) for o in Specifier.OPERATORS):
79
+ s = '~=' + s
80
+ return cls(
81
+ specifier=Specifier(s),
82
+ opts=o,
83
+ )
84
+
85
+ def contains(self, iv: InterpVersion) -> bool:
86
+ return self.specifier.contains(iv.version) and self.opts == iv.opts
87
+
88
+
89
+ @dc.dataclass(frozen=True)
90
+ class Interp:
91
+ exe: str
92
+ version: InterpVersion
omdev/mypy/__init__.py ADDED
File without changes
omdev/mypy/debug.py ADDED
@@ -0,0 +1,86 @@
1
+ import importlib.machinery
2
+ import re
3
+ import sys
4
+
5
+
6
+ def _is_instance_or_subclass(obj, cls):
7
+ return (isinstance(obj, type) and issubclass(obj, cls)) or isinstance(obj, cls)
8
+
9
+
10
+ class MypyDebugPathFinder(importlib.machinery.PathFinder):
11
+
12
+ @classmethod
13
+ def _get_spec(cls, fullname, path, target=None): # noqa
14
+ namespace_path = []
15
+ for entry in path:
16
+ if not isinstance(entry, (str, bytes)):
17
+ continue
18
+ finder = cls._path_importer_cache(entry) # type: ignore # noqa
19
+ if finder is not None:
20
+ if isinstance(finder, importlib.machinery.FileFinder):
21
+ finder = importlib.machinery.FileFinder(
22
+ finder.path,
23
+ *[
24
+ (i, [s]) for s, i in finder._loaders # type: ignore # noqa
25
+ if not _is_instance_or_subclass(i, importlib.machinery.ExtensionFileLoader)
26
+ ],
27
+ )
28
+ if hasattr(finder, 'find_spec'):
29
+ spec = finder.find_spec(fullname, target)
30
+ else:
31
+ spec = cls._legacy_get_spec(fullname, finder) # type: ignore # noqa
32
+ if spec is None:
33
+ continue
34
+ if spec.loader is not None:
35
+ return spec
36
+ portions = spec.submodule_search_locations
37
+ if portions is None:
38
+ raise ImportError('spec missing loader')
39
+ namespace_path.extend(portions)
40
+ return None
41
+
42
+ @classmethod
43
+ def find_spec(cls, fullname, path=None, target=None): # noqa
44
+ if not fullname.startswith('mypy.') and fullname != 'mypy':
45
+ return None
46
+ if path is None:
47
+ path = sys.path
48
+ spec = cls._get_spec(fullname, path, target)
49
+ if spec is None:
50
+ return None
51
+ elif spec.loader is None:
52
+ namespace_path = spec.submodule_search_locations
53
+ if namespace_path:
54
+ spec.origin = None
55
+ spec.submodule_search_locations = importlib.machinery._NamespacePath( # type: ignore # noqa
56
+ fullname,
57
+ namespace_path,
58
+ cls._get_spec,
59
+ )
60
+ return spec
61
+ else:
62
+ return None
63
+ else:
64
+ return spec
65
+
66
+
67
+ def _main():
68
+ for i, e in enumerate(sys.meta_path): # noqa
69
+ if _is_instance_or_subclass(e, importlib.machinery.PathFinder):
70
+ break
71
+ sys.meta_path.insert(i, MypyDebugPathFinder) # noqa
72
+ sys.path_importer_cache.clear()
73
+ importlib.invalidate_caches()
74
+
75
+ from mypy.__main__ import console_entry # noqa
76
+
77
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
78
+
79
+ if not any(k in sys.argv[1:] for k in ['--show-traceback', '--tb']):
80
+ sys.argv.insert(1, '--show-traceback')
81
+
82
+ console_entry()
83
+
84
+
85
+ if __name__ == '__main__':
86
+ _main()
@@ -0,0 +1 @@
1
+ # @omlish-lite
@@ -0,0 +1,4 @@
1
+ if __name__ == '__main__':
2
+ from .cli import _main
3
+
4
+ _main()