omdev 0.0.0.dev181__py3-none-any.whl → 0.0.0.dev183__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omdev/interp/inject.py +1 -1
- omdev/interp/pyenv/inject.py +1 -1
- omdev/interp/pyenv/install.py +251 -0
- omdev/interp/pyenv/provider.py +144 -0
- omdev/interp/pyenv/pyenv.py +0 -383
- omdev/scripts/interp.py +104 -102
- omdev/scripts/pyproject.py +225 -212
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/RECORD +13 -11
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev181.dist-info → omdev-0.0.0.dev183.dist-info}/top_level.txt +0 -0
omdev/interp/pyenv/pyenv.py
CHANGED
@@ -10,32 +10,14 @@ TODO:
|
|
10
10
|
- optionally install / upgrade pyenv itself
|
11
11
|
- new vers dont need these custom mac opts, only run on old vers
|
12
12
|
"""
|
13
|
-
import abc
|
14
|
-
import dataclasses as dc
|
15
|
-
import itertools
|
16
|
-
import logging
|
17
13
|
import os.path
|
18
14
|
import shutil
|
19
|
-
import sys
|
20
15
|
import typing as ta
|
21
16
|
|
22
17
|
from omlish.asyncs.asyncio.subprocesses import asyncio_subprocesses
|
23
18
|
from omlish.lite.cached import async_cached_nullary
|
24
|
-
from omlish.lite.cached import cached_nullary
|
25
19
|
from omlish.lite.check import check
|
26
20
|
|
27
|
-
from ...packaging.versions import InvalidVersion
|
28
|
-
from ...packaging.versions import Version
|
29
|
-
from ..inspect import InterpInspector
|
30
|
-
from ..providers.base import InterpProvider
|
31
|
-
from ..types import Interp
|
32
|
-
from ..types import InterpOpts
|
33
|
-
from ..types import InterpSpecifier
|
34
|
-
from ..types import InterpVersion
|
35
|
-
|
36
|
-
|
37
|
-
##
|
38
|
-
|
39
21
|
|
40
22
|
class Pyenv:
|
41
23
|
def __init__(
|
@@ -102,368 +84,3 @@ class Pyenv:
|
|
102
84
|
return False
|
103
85
|
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
104
86
|
return True
|
105
|
-
|
106
|
-
|
107
|
-
##
|
108
|
-
|
109
|
-
|
110
|
-
@dc.dataclass(frozen=True)
|
111
|
-
class PyenvInstallOpts:
|
112
|
-
opts: ta.Sequence[str] = ()
|
113
|
-
conf_opts: ta.Sequence[str] = ()
|
114
|
-
cflags: ta.Sequence[str] = ()
|
115
|
-
ldflags: ta.Sequence[str] = ()
|
116
|
-
env: ta.Mapping[str, str] = dc.field(default_factory=dict)
|
117
|
-
|
118
|
-
def merge(self, *others: 'PyenvInstallOpts') -> 'PyenvInstallOpts':
|
119
|
-
return PyenvInstallOpts(
|
120
|
-
opts=list(itertools.chain.from_iterable(o.opts for o in [self, *others])),
|
121
|
-
conf_opts=list(itertools.chain.from_iterable(o.conf_opts for o in [self, *others])),
|
122
|
-
cflags=list(itertools.chain.from_iterable(o.cflags for o in [self, *others])),
|
123
|
-
ldflags=list(itertools.chain.from_iterable(o.ldflags for o in [self, *others])),
|
124
|
-
env=dict(itertools.chain.from_iterable(o.env.items() for o in [self, *others])),
|
125
|
-
)
|
126
|
-
|
127
|
-
|
128
|
-
# TODO: https://github.com/pyenv/pyenv/blob/master/plugins/python-build/README.md#building-for-maximum-performance
|
129
|
-
DEFAULT_PYENV_INSTALL_OPTS = PyenvInstallOpts(
|
130
|
-
opts=[
|
131
|
-
'-s',
|
132
|
-
'-v',
|
133
|
-
'-k',
|
134
|
-
],
|
135
|
-
conf_opts=[
|
136
|
-
# FIXME: breaks on mac for older py's
|
137
|
-
'--enable-loadable-sqlite-extensions',
|
138
|
-
|
139
|
-
# '--enable-shared',
|
140
|
-
|
141
|
-
'--enable-optimizations',
|
142
|
-
'--with-lto',
|
143
|
-
|
144
|
-
# '--enable-profiling', # ?
|
145
|
-
|
146
|
-
# '--enable-ipv6', # ?
|
147
|
-
],
|
148
|
-
cflags=[
|
149
|
-
# '-march=native',
|
150
|
-
# '-mtune=native',
|
151
|
-
],
|
152
|
-
)
|
153
|
-
|
154
|
-
DEBUG_PYENV_INSTALL_OPTS = PyenvInstallOpts(opts=['-g'])
|
155
|
-
|
156
|
-
THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
|
157
|
-
|
158
|
-
|
159
|
-
#
|
160
|
-
|
161
|
-
|
162
|
-
class PyenvInstallOptsProvider(abc.ABC):
|
163
|
-
@abc.abstractmethod
|
164
|
-
def opts(self) -> ta.Awaitable[PyenvInstallOpts]:
|
165
|
-
raise NotImplementedError
|
166
|
-
|
167
|
-
|
168
|
-
class LinuxPyenvInstallOpts(PyenvInstallOptsProvider):
|
169
|
-
async def opts(self) -> PyenvInstallOpts:
|
170
|
-
return PyenvInstallOpts()
|
171
|
-
|
172
|
-
|
173
|
-
class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
|
174
|
-
@cached_nullary
|
175
|
-
def framework_opts(self) -> PyenvInstallOpts:
|
176
|
-
return PyenvInstallOpts(conf_opts=['--enable-framework'])
|
177
|
-
|
178
|
-
@cached_nullary
|
179
|
-
def has_brew(self) -> bool:
|
180
|
-
return shutil.which('brew') is not None
|
181
|
-
|
182
|
-
BREW_DEPS: ta.Sequence[str] = [
|
183
|
-
'openssl',
|
184
|
-
'readline',
|
185
|
-
'sqlite3',
|
186
|
-
'zlib',
|
187
|
-
]
|
188
|
-
|
189
|
-
@async_cached_nullary
|
190
|
-
async def brew_deps_opts(self) -> PyenvInstallOpts:
|
191
|
-
cflags = []
|
192
|
-
ldflags = []
|
193
|
-
for dep in self.BREW_DEPS:
|
194
|
-
dep_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', dep)
|
195
|
-
cflags.append(f'-I{dep_prefix}/include')
|
196
|
-
ldflags.append(f'-L{dep_prefix}/lib')
|
197
|
-
return PyenvInstallOpts(
|
198
|
-
cflags=cflags,
|
199
|
-
ldflags=ldflags,
|
200
|
-
)
|
201
|
-
|
202
|
-
@async_cached_nullary
|
203
|
-
async def brew_tcl_opts(self) -> PyenvInstallOpts:
|
204
|
-
if await asyncio_subprocesses.try_output('brew', '--prefix', 'tcl-tk') is None:
|
205
|
-
return PyenvInstallOpts()
|
206
|
-
|
207
|
-
tcl_tk_prefix = await asyncio_subprocesses.check_output_str('brew', '--prefix', 'tcl-tk')
|
208
|
-
tcl_tk_ver_str = await asyncio_subprocesses.check_output_str('brew', 'ls', '--versions', 'tcl-tk')
|
209
|
-
tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
|
210
|
-
|
211
|
-
return PyenvInstallOpts(conf_opts=[
|
212
|
-
f"--with-tcltk-includes='-I{tcl_tk_prefix}/include'",
|
213
|
-
f"--with-tcltk-libs='-L{tcl_tk_prefix}/lib -ltcl{tcl_tk_ver} -ltk{tcl_tk_ver}'",
|
214
|
-
])
|
215
|
-
|
216
|
-
# @cached_nullary
|
217
|
-
# def brew_ssl_opts(self) -> PyenvInstallOpts:
|
218
|
-
# pkg_config_path = subprocess_check_output_str('brew', '--prefix', 'openssl')
|
219
|
-
# if 'PKG_CONFIG_PATH' in os.environ:
|
220
|
-
# pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
|
221
|
-
# return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
|
222
|
-
|
223
|
-
async def opts(self) -> PyenvInstallOpts:
|
224
|
-
return PyenvInstallOpts().merge(
|
225
|
-
self.framework_opts(),
|
226
|
-
await self.brew_deps_opts(),
|
227
|
-
await self.brew_tcl_opts(),
|
228
|
-
# self.brew_ssl_opts(),
|
229
|
-
)
|
230
|
-
|
231
|
-
|
232
|
-
PLATFORM_PYENV_INSTALL_OPTS: ta.Dict[str, PyenvInstallOptsProvider] = {
|
233
|
-
'darwin': DarwinPyenvInstallOpts(),
|
234
|
-
'linux': LinuxPyenvInstallOpts(),
|
235
|
-
}
|
236
|
-
|
237
|
-
|
238
|
-
##
|
239
|
-
|
240
|
-
|
241
|
-
class PyenvVersionInstaller:
|
242
|
-
"""
|
243
|
-
Messy: can install freethreaded build with a 't' suffixed version str _or_ by THREADED_PYENV_INSTALL_OPTS - need
|
244
|
-
latter to build custom interp with ft, need former to use canned / blessed interps. Muh.
|
245
|
-
"""
|
246
|
-
|
247
|
-
def __init__(
|
248
|
-
self,
|
249
|
-
version: str,
|
250
|
-
opts: ta.Optional[PyenvInstallOpts] = None,
|
251
|
-
interp_opts: InterpOpts = InterpOpts(),
|
252
|
-
*,
|
253
|
-
pyenv: Pyenv,
|
254
|
-
|
255
|
-
install_name: ta.Optional[str] = None,
|
256
|
-
no_default_opts: bool = False,
|
257
|
-
) -> None:
|
258
|
-
super().__init__()
|
259
|
-
|
260
|
-
self._version = version
|
261
|
-
self._given_opts = opts
|
262
|
-
self._interp_opts = interp_opts
|
263
|
-
self._given_install_name = install_name
|
264
|
-
|
265
|
-
self._no_default_opts = no_default_opts
|
266
|
-
self._pyenv = pyenv
|
267
|
-
|
268
|
-
@property
|
269
|
-
def version(self) -> str:
|
270
|
-
return self._version
|
271
|
-
|
272
|
-
@async_cached_nullary
|
273
|
-
async def opts(self) -> PyenvInstallOpts:
|
274
|
-
opts = self._given_opts
|
275
|
-
if self._no_default_opts:
|
276
|
-
if opts is None:
|
277
|
-
opts = PyenvInstallOpts()
|
278
|
-
else:
|
279
|
-
lst = [self._given_opts if self._given_opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
|
280
|
-
if self._interp_opts.debug:
|
281
|
-
lst.append(DEBUG_PYENV_INSTALL_OPTS)
|
282
|
-
if self._interp_opts.threaded:
|
283
|
-
lst.append(THREADED_PYENV_INSTALL_OPTS)
|
284
|
-
lst.append(await PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
|
285
|
-
opts = PyenvInstallOpts().merge(*lst)
|
286
|
-
return opts
|
287
|
-
|
288
|
-
@cached_nullary
|
289
|
-
def install_name(self) -> str:
|
290
|
-
if self._given_install_name is not None:
|
291
|
-
return self._given_install_name
|
292
|
-
return self._version + ('-debug' if self._interp_opts.debug else '')
|
293
|
-
|
294
|
-
@async_cached_nullary
|
295
|
-
async def install_dir(self) -> str:
|
296
|
-
return str(os.path.join(check.not_none(await self._pyenv.root()), 'versions', self.install_name()))
|
297
|
-
|
298
|
-
@async_cached_nullary
|
299
|
-
async def install(self) -> str:
|
300
|
-
opts = await self.opts()
|
301
|
-
env = {**os.environ, **opts.env}
|
302
|
-
for k, l in [
|
303
|
-
('CFLAGS', opts.cflags),
|
304
|
-
('LDFLAGS', opts.ldflags),
|
305
|
-
('PYTHON_CONFIGURE_OPTS', opts.conf_opts),
|
306
|
-
]:
|
307
|
-
v = ' '.join(l)
|
308
|
-
if k in os.environ:
|
309
|
-
v += ' ' + os.environ[k]
|
310
|
-
env[k] = v
|
311
|
-
|
312
|
-
conf_args = [
|
313
|
-
*opts.opts,
|
314
|
-
self._version,
|
315
|
-
]
|
316
|
-
|
317
|
-
full_args: ta.List[str]
|
318
|
-
if self._given_install_name is not None:
|
319
|
-
full_args = [
|
320
|
-
os.path.join(check.not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
|
321
|
-
*conf_args,
|
322
|
-
await self.install_dir(),
|
323
|
-
]
|
324
|
-
else:
|
325
|
-
full_args = [
|
326
|
-
await self._pyenv.exe(),
|
327
|
-
'install',
|
328
|
-
*conf_args,
|
329
|
-
]
|
330
|
-
|
331
|
-
await asyncio_subprocesses.check_call(
|
332
|
-
*full_args,
|
333
|
-
env=env,
|
334
|
-
)
|
335
|
-
|
336
|
-
exe = os.path.join(await self.install_dir(), 'bin', 'python')
|
337
|
-
if not os.path.isfile(exe):
|
338
|
-
raise RuntimeError(f'Interpreter not found: {exe}')
|
339
|
-
return exe
|
340
|
-
|
341
|
-
|
342
|
-
##
|
343
|
-
|
344
|
-
|
345
|
-
class PyenvInterpProvider(InterpProvider):
|
346
|
-
@dc.dataclass(frozen=True)
|
347
|
-
class Options:
|
348
|
-
inspect: bool = False
|
349
|
-
|
350
|
-
try_update: bool = False
|
351
|
-
|
352
|
-
def __init__(
|
353
|
-
self,
|
354
|
-
options: Options = Options(),
|
355
|
-
*,
|
356
|
-
pyenv: Pyenv,
|
357
|
-
inspector: InterpInspector,
|
358
|
-
log: ta.Optional[logging.Logger] = None,
|
359
|
-
) -> None:
|
360
|
-
super().__init__()
|
361
|
-
|
362
|
-
self._options = options
|
363
|
-
|
364
|
-
self._pyenv = pyenv
|
365
|
-
self._inspector = inspector
|
366
|
-
self._log = log
|
367
|
-
|
368
|
-
#
|
369
|
-
|
370
|
-
@staticmethod
|
371
|
-
def guess_version(s: str) -> ta.Optional[InterpVersion]:
|
372
|
-
def strip_sfx(s: str, sfx: str) -> ta.Tuple[str, bool]:
|
373
|
-
if s.endswith(sfx):
|
374
|
-
return s[:-len(sfx)], True
|
375
|
-
return s, False
|
376
|
-
ok = {}
|
377
|
-
s, ok['debug'] = strip_sfx(s, '-debug')
|
378
|
-
s, ok['threaded'] = strip_sfx(s, 't')
|
379
|
-
try:
|
380
|
-
v = Version(s)
|
381
|
-
except InvalidVersion:
|
382
|
-
return None
|
383
|
-
return InterpVersion(v, InterpOpts(**ok))
|
384
|
-
|
385
|
-
class Installed(ta.NamedTuple):
|
386
|
-
name: str
|
387
|
-
exe: str
|
388
|
-
version: InterpVersion
|
389
|
-
|
390
|
-
async def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
|
391
|
-
iv: ta.Optional[InterpVersion]
|
392
|
-
if self._options.inspect:
|
393
|
-
try:
|
394
|
-
iv = check.not_none(await self._inspector.inspect(ep)).iv
|
395
|
-
except Exception as e: # noqa
|
396
|
-
return None
|
397
|
-
else:
|
398
|
-
iv = self.guess_version(vn)
|
399
|
-
if iv is None:
|
400
|
-
return None
|
401
|
-
return PyenvInterpProvider.Installed(
|
402
|
-
name=vn,
|
403
|
-
exe=ep,
|
404
|
-
version=iv,
|
405
|
-
)
|
406
|
-
|
407
|
-
async def installed(self) -> ta.Sequence[Installed]:
|
408
|
-
ret: ta.List[PyenvInterpProvider.Installed] = []
|
409
|
-
for vn, ep in await self._pyenv.version_exes():
|
410
|
-
if (i := await self._make_installed(vn, ep)) is None:
|
411
|
-
if self._log is not None:
|
412
|
-
self._log.debug('Invalid pyenv version: %s', vn)
|
413
|
-
continue
|
414
|
-
ret.append(i)
|
415
|
-
return ret
|
416
|
-
|
417
|
-
#
|
418
|
-
|
419
|
-
async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
420
|
-
return [i.version for i in await self.installed()]
|
421
|
-
|
422
|
-
async def get_installed_version(self, version: InterpVersion) -> Interp:
|
423
|
-
for i in await self.installed():
|
424
|
-
if i.version == version:
|
425
|
-
return Interp(
|
426
|
-
exe=i.exe,
|
427
|
-
version=i.version,
|
428
|
-
)
|
429
|
-
raise KeyError(version)
|
430
|
-
|
431
|
-
#
|
432
|
-
|
433
|
-
async def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
434
|
-
lst = []
|
435
|
-
|
436
|
-
for vs in await self._pyenv.installable_versions():
|
437
|
-
if (iv := self.guess_version(vs)) is None:
|
438
|
-
continue
|
439
|
-
if iv.opts.debug:
|
440
|
-
raise Exception('Pyenv installable versions not expected to have debug suffix')
|
441
|
-
for d in [False, True]:
|
442
|
-
lst.append(dc.replace(iv, opts=dc.replace(iv.opts, debug=d)))
|
443
|
-
|
444
|
-
return lst
|
445
|
-
|
446
|
-
async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
|
447
|
-
lst = await self._get_installable_versions(spec)
|
448
|
-
|
449
|
-
if self._options.try_update and not any(v in spec for v in lst):
|
450
|
-
if self._pyenv.update():
|
451
|
-
lst = await self._get_installable_versions(spec)
|
452
|
-
|
453
|
-
return lst
|
454
|
-
|
455
|
-
async def install_version(self, version: InterpVersion) -> Interp:
|
456
|
-
inst_version = str(version.version)
|
457
|
-
inst_opts = version.opts
|
458
|
-
if inst_opts.threaded:
|
459
|
-
inst_version += 't'
|
460
|
-
inst_opts = dc.replace(inst_opts, threaded=False)
|
461
|
-
|
462
|
-
installer = PyenvVersionInstaller(
|
463
|
-
inst_version,
|
464
|
-
interp_opts=inst_opts,
|
465
|
-
pyenv=self._pyenv,
|
466
|
-
)
|
467
|
-
|
468
|
-
exe = await installer.install()
|
469
|
-
return Interp(exe, version)
|
omdev/scripts/interp.py
CHANGED
@@ -4262,6 +4262,88 @@ class InterpInspector:
|
|
4262
4262
|
return ret
|
4263
4263
|
|
4264
4264
|
|
4265
|
+
########################################
|
4266
|
+
# ../pyenv/pyenv.py
|
4267
|
+
"""
|
4268
|
+
TODO:
|
4269
|
+
- custom tags
|
4270
|
+
- 'aliases'
|
4271
|
+
- https://github.com/pyenv/pyenv/pull/2966
|
4272
|
+
- https://github.com/pyenv/pyenv/issues/218 (lol)
|
4273
|
+
- probably need custom (temp?) definition file
|
4274
|
+
- *or* python-build directly just into the versions dir?
|
4275
|
+
- optionally install / upgrade pyenv itself
|
4276
|
+
- new vers dont need these custom mac opts, only run on old vers
|
4277
|
+
"""
|
4278
|
+
|
4279
|
+
|
4280
|
+
class Pyenv:
|
4281
|
+
def __init__(
|
4282
|
+
self,
|
4283
|
+
*,
|
4284
|
+
root: ta.Optional[str] = None,
|
4285
|
+
) -> None:
|
4286
|
+
if root is not None and not (isinstance(root, str) and root):
|
4287
|
+
raise ValueError(f'pyenv_root: {root!r}')
|
4288
|
+
|
4289
|
+
super().__init__()
|
4290
|
+
|
4291
|
+
self._root_kw = root
|
4292
|
+
|
4293
|
+
@async_cached_nullary
|
4294
|
+
async def root(self) -> ta.Optional[str]:
|
4295
|
+
if self._root_kw is not None:
|
4296
|
+
return self._root_kw
|
4297
|
+
|
4298
|
+
if shutil.which('pyenv'):
|
4299
|
+
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
4300
|
+
|
4301
|
+
d = os.path.expanduser('~/.pyenv')
|
4302
|
+
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
4303
|
+
return d
|
4304
|
+
|
4305
|
+
return None
|
4306
|
+
|
4307
|
+
@async_cached_nullary
|
4308
|
+
async def exe(self) -> str:
|
4309
|
+
return os.path.join(check.not_none(await self.root()), 'bin', 'pyenv')
|
4310
|
+
|
4311
|
+
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
4312
|
+
if (root := await self.root()) is None:
|
4313
|
+
return []
|
4314
|
+
ret = []
|
4315
|
+
vp = os.path.join(root, 'versions')
|
4316
|
+
if os.path.isdir(vp):
|
4317
|
+
for dn in os.listdir(vp):
|
4318
|
+
ep = os.path.join(vp, dn, 'bin', 'python')
|
4319
|
+
if not os.path.isfile(ep):
|
4320
|
+
continue
|
4321
|
+
ret.append((dn, ep))
|
4322
|
+
return ret
|
4323
|
+
|
4324
|
+
async def installable_versions(self) -> ta.List[str]:
|
4325
|
+
if await self.root() is None:
|
4326
|
+
return []
|
4327
|
+
ret = []
|
4328
|
+
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
4329
|
+
for l in s.splitlines():
|
4330
|
+
if not l.startswith(' '):
|
4331
|
+
continue
|
4332
|
+
l = l.strip()
|
4333
|
+
if not l:
|
4334
|
+
continue
|
4335
|
+
ret.append(l)
|
4336
|
+
return ret
|
4337
|
+
|
4338
|
+
async def update(self) -> bool:
|
4339
|
+
if (root := await self.root()) is None:
|
4340
|
+
return False
|
4341
|
+
if not os.path.isdir(os.path.join(root, '.git')):
|
4342
|
+
return False
|
4343
|
+
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
4344
|
+
return True
|
4345
|
+
|
4346
|
+
|
4265
4347
|
########################################
|
4266
4348
|
# ../resolvers.py
|
4267
4349
|
|
@@ -4500,88 +4582,7 @@ class SystemInterpProvider(InterpProvider):
|
|
4500
4582
|
|
4501
4583
|
|
4502
4584
|
########################################
|
4503
|
-
# ../pyenv/
|
4504
|
-
"""
|
4505
|
-
TODO:
|
4506
|
-
- custom tags
|
4507
|
-
- 'aliases'
|
4508
|
-
- https://github.com/pyenv/pyenv/pull/2966
|
4509
|
-
- https://github.com/pyenv/pyenv/issues/218 (lol)
|
4510
|
-
- probably need custom (temp?) definition file
|
4511
|
-
- *or* python-build directly just into the versions dir?
|
4512
|
-
- optionally install / upgrade pyenv itself
|
4513
|
-
- new vers dont need these custom mac opts, only run on old vers
|
4514
|
-
"""
|
4515
|
-
|
4516
|
-
|
4517
|
-
##
|
4518
|
-
|
4519
|
-
|
4520
|
-
class Pyenv:
|
4521
|
-
def __init__(
|
4522
|
-
self,
|
4523
|
-
*,
|
4524
|
-
root: ta.Optional[str] = None,
|
4525
|
-
) -> None:
|
4526
|
-
if root is not None and not (isinstance(root, str) and root):
|
4527
|
-
raise ValueError(f'pyenv_root: {root!r}')
|
4528
|
-
|
4529
|
-
super().__init__()
|
4530
|
-
|
4531
|
-
self._root_kw = root
|
4532
|
-
|
4533
|
-
@async_cached_nullary
|
4534
|
-
async def root(self) -> ta.Optional[str]:
|
4535
|
-
if self._root_kw is not None:
|
4536
|
-
return self._root_kw
|
4537
|
-
|
4538
|
-
if shutil.which('pyenv'):
|
4539
|
-
return await asyncio_subprocesses.check_output_str('pyenv', 'root')
|
4540
|
-
|
4541
|
-
d = os.path.expanduser('~/.pyenv')
|
4542
|
-
if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
|
4543
|
-
return d
|
4544
|
-
|
4545
|
-
return None
|
4546
|
-
|
4547
|
-
@async_cached_nullary
|
4548
|
-
async def exe(self) -> str:
|
4549
|
-
return os.path.join(check.not_none(await self.root()), 'bin', 'pyenv')
|
4550
|
-
|
4551
|
-
async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
|
4552
|
-
if (root := await self.root()) is None:
|
4553
|
-
return []
|
4554
|
-
ret = []
|
4555
|
-
vp = os.path.join(root, 'versions')
|
4556
|
-
if os.path.isdir(vp):
|
4557
|
-
for dn in os.listdir(vp):
|
4558
|
-
ep = os.path.join(vp, dn, 'bin', 'python')
|
4559
|
-
if not os.path.isfile(ep):
|
4560
|
-
continue
|
4561
|
-
ret.append((dn, ep))
|
4562
|
-
return ret
|
4563
|
-
|
4564
|
-
async def installable_versions(self) -> ta.List[str]:
|
4565
|
-
if await self.root() is None:
|
4566
|
-
return []
|
4567
|
-
ret = []
|
4568
|
-
s = await asyncio_subprocesses.check_output_str(await self.exe(), 'install', '--list')
|
4569
|
-
for l in s.splitlines():
|
4570
|
-
if not l.startswith(' '):
|
4571
|
-
continue
|
4572
|
-
l = l.strip()
|
4573
|
-
if not l:
|
4574
|
-
continue
|
4575
|
-
ret.append(l)
|
4576
|
-
return ret
|
4577
|
-
|
4578
|
-
async def update(self) -> bool:
|
4579
|
-
if (root := await self.root()) is None:
|
4580
|
-
return False
|
4581
|
-
if not os.path.isdir(os.path.join(root, '.git')):
|
4582
|
-
return False
|
4583
|
-
await asyncio_subprocesses.check_call('git', 'pull', cwd=root)
|
4584
|
-
return True
|
4585
|
+
# ../pyenv/install.py
|
4585
4586
|
|
4586
4587
|
|
4587
4588
|
##
|
@@ -4819,7 +4820,27 @@ class PyenvVersionInstaller:
|
|
4819
4820
|
return exe
|
4820
4821
|
|
4821
4822
|
|
4822
|
-
|
4823
|
+
########################################
|
4824
|
+
# ../providers/inject.py
|
4825
|
+
|
4826
|
+
|
4827
|
+
def bind_interp_providers() -> InjectorBindings:
|
4828
|
+
lst: ta.List[InjectorBindingOrBindings] = [
|
4829
|
+
inj.bind_array(InterpProvider),
|
4830
|
+
inj.bind_array_type(InterpProvider, InterpProviders),
|
4831
|
+
|
4832
|
+
inj.bind(RunningInterpProvider, singleton=True),
|
4833
|
+
inj.bind(InterpProvider, to_key=RunningInterpProvider, array=True),
|
4834
|
+
|
4835
|
+
inj.bind(SystemInterpProvider, singleton=True),
|
4836
|
+
inj.bind(InterpProvider, to_key=SystemInterpProvider, array=True),
|
4837
|
+
]
|
4838
|
+
|
4839
|
+
return inj.as_bindings(*lst)
|
4840
|
+
|
4841
|
+
|
4842
|
+
########################################
|
4843
|
+
# ../pyenv/provider.py
|
4823
4844
|
|
4824
4845
|
|
4825
4846
|
class PyenvInterpProvider(InterpProvider):
|
@@ -4949,25 +4970,6 @@ class PyenvInterpProvider(InterpProvider):
|
|
4949
4970
|
return Interp(exe, version)
|
4950
4971
|
|
4951
4972
|
|
4952
|
-
########################################
|
4953
|
-
# ../providers/inject.py
|
4954
|
-
|
4955
|
-
|
4956
|
-
def bind_interp_providers() -> InjectorBindings:
|
4957
|
-
lst: ta.List[InjectorBindingOrBindings] = [
|
4958
|
-
inj.bind_array(InterpProvider),
|
4959
|
-
inj.bind_array_type(InterpProvider, InterpProviders),
|
4960
|
-
|
4961
|
-
inj.bind(RunningInterpProvider, singleton=True),
|
4962
|
-
inj.bind(InterpProvider, to_key=RunningInterpProvider, array=True),
|
4963
|
-
|
4964
|
-
inj.bind(SystemInterpProvider, singleton=True),
|
4965
|
-
inj.bind(InterpProvider, to_key=SystemInterpProvider, array=True),
|
4966
|
-
]
|
4967
|
-
|
4968
|
-
return inj.as_bindings(*lst)
|
4969
|
-
|
4970
|
-
|
4971
4973
|
########################################
|
4972
4974
|
# ../pyenv/inject.py
|
4973
4975
|
|