omdev 0.0.0.dev147__tar.gz → 0.0.0.dev149__tar.gz

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 (167) hide show
  1. {omdev-0.0.0.dev147/omdev.egg-info → omdev-0.0.0.dev149}/PKG-INFO +2 -2
  2. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/.manifests.json +12 -0
  3. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/amalg/amalg.py +1 -0
  4. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cli/clicli.py +1 -1
  5. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/imgur.py +1 -1
  6. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/cli.py +11 -6
  7. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/inspect.py +5 -6
  8. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/providers.py +6 -6
  9. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/pyenv.py +77 -78
  10. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/resolvers.py +11 -10
  11. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/system.py +8 -8
  12. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/types.py +2 -0
  13. omdev-0.0.0.dev149/omdev/manifests/__main__.py +11 -0
  14. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/manifests/build.py +2 -76
  15. omdev-0.0.0.dev149/omdev/manifests/main.py +84 -0
  16. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pycharm/cli.py +1 -1
  17. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pyproject/cli.py +21 -15
  18. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/interp.py +564 -134
  19. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/pyproject.py +1404 -975
  20. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/doc.py +1 -1
  21. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/docker.py +1 -1
  22. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/git.py +1 -1
  23. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/json/parsing.py +1 -1
  24. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/notebook.py +1 -1
  25. omdev-0.0.0.dev149/omdev/tools/pawk/__init__.py +0 -0
  26. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/pip.py +1 -1
  27. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/prof.py +1 -1
  28. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/sqlrepl.py +1 -1
  29. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149/omdev.egg-info}/PKG-INFO +2 -2
  30. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev.egg-info/SOURCES.txt +2 -0
  31. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev.egg-info/requires.txt +1 -1
  32. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/pyproject.toml +2 -2
  33. omdev-0.0.0.dev147/omdev/toml/__init__.py +0 -1
  34. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/LICENSE +0 -0
  35. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/MANIFEST.in +0 -0
  36. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/README.rst +0 -0
  37. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/__about__.py +0 -0
  38. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/__init__.py +0 -0
  39. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/amalg/__init__.py +0 -0
  40. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/amalg/__main__.py +0 -0
  41. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/antlr/__init__.py +0 -0
  42. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/antlr/consts.py +0 -0
  43. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/antlr/gen.py +0 -0
  44. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/bracepy.py +0 -0
  45. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/__init__.py +0 -0
  46. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/compute/__init__.py +0 -0
  47. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/compute/cache.py +0 -0
  48. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/compute/contexts.py +0 -0
  49. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/compute/currents.py +0 -0
  50. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/compute/fns.py +0 -0
  51. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/compute/resolvers.py +0 -0
  52. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/compute/storage.py +0 -0
  53. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/compute/types.py +0 -0
  54. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/data/__init__.py +0 -0
  55. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/data/actions.py +0 -0
  56. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/data/cache.py +0 -0
  57. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/data/consts.py +0 -0
  58. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/data/defaults.py +0 -0
  59. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/data/manifests.py +0 -0
  60. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cache/data/specs.py +0 -0
  61. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/__init__.py +0 -0
  62. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_boilerplate.cc +0 -0
  63. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/LICENSE +0 -0
  64. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/__init__.py +0 -0
  65. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/build_ext.py +0 -0
  66. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/compilers/__init__.py +0 -0
  67. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/compilers/ccompiler.py +0 -0
  68. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/compilers/options.py +0 -0
  69. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/compilers/unixccompiler.py +0 -0
  70. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/dir_util.py +0 -0
  71. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/errors.py +0 -0
  72. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/extension.py +0 -0
  73. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/file_util.py +0 -0
  74. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/modified.py +0 -0
  75. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/spawn.py +0 -0
  76. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/sysconfig.py +0 -0
  77. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/util.py +0 -0
  78. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/_distutils/version.py +0 -0
  79. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/build.py +0 -0
  80. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/cmake.py +0 -0
  81. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/importhook.py +0 -0
  82. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/magic.py +0 -0
  83. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cexts/scan.py +0 -0
  84. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/classdot.py +0 -0
  85. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cli/__init__.py +0 -0
  86. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cli/__main__.py +0 -0
  87. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cli/_pathhack.py +0 -0
  88. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cli/install.py +0 -0
  89. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cli/main.py +0 -0
  90. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cli/managers.py +0 -0
  91. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cli/types.py +0 -0
  92. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/clipboard/__init__.py +0 -0
  93. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/clipboard/clipboard.py +0 -0
  94. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/clipboard/darwin_cf.py +0 -0
  95. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/clipboard/linux_x11.py +0 -0
  96. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/cmake.py +0 -0
  97. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/findimports.py +0 -0
  98. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/git.py +0 -0
  99. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/__init__.py +0 -0
  100. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/__main__.py +0 -0
  101. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/interp/standalone.py +0 -0
  102. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/magic/__init__.py +0 -0
  103. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/magic/find.py +0 -0
  104. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/magic/magic.py +0 -0
  105. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/magic/prepare.py +0 -0
  106. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/magic/styles.py +0 -0
  107. {omdev-0.0.0.dev147/omdev/mypy → omdev-0.0.0.dev149/omdev/manifests}/__init__.py +0 -0
  108. {omdev-0.0.0.dev147/omdev/packaging → omdev-0.0.0.dev149/omdev/mypy}/__init__.py +0 -0
  109. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/mypy/debug.py +0 -0
  110. {omdev-0.0.0.dev147/omdev/precheck → omdev-0.0.0.dev149/omdev/packaging}/__init__.py +0 -0
  111. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/packaging/marshal.py +0 -0
  112. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/packaging/names.py +0 -0
  113. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/packaging/requires.py +0 -0
  114. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/packaging/specifiers.py +0 -0
  115. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/packaging/versions.py +0 -0
  116. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pip.py +0 -0
  117. {omdev-0.0.0.dev147/omdev/ptk/apps → omdev-0.0.0.dev149/omdev/precheck}/__init__.py +0 -0
  118. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/precheck/__main__.py +0 -0
  119. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/precheck/base.py +0 -0
  120. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/precheck/git.py +0 -0
  121. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/precheck/lite.py +0 -0
  122. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/precheck/main.py +0 -0
  123. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/precheck/manifests.py +0 -0
  124. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/precheck/scripts.py +0 -0
  125. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/ptk/__init__.py +0 -0
  126. {omdev-0.0.0.dev147/omdev/pycharm → omdev-0.0.0.dev149/omdev/ptk/apps}/__init__.py +0 -0
  127. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/ptk/apps/ncdu.py +0 -0
  128. {omdev-0.0.0.dev147/omdev/tools/json → omdev-0.0.0.dev149/omdev/pycharm}/__init__.py +0 -0
  129. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pycharm/__main__.py +0 -0
  130. {omdev-0.0.0.dev147/omdev/manifests → omdev-0.0.0.dev149/omdev/pyproject}/__init__.py +0 -0
  131. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pyproject/__main__.py +0 -0
  132. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pyproject/cexts.py +0 -0
  133. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pyproject/configs.py +0 -0
  134. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pyproject/pkg.py +0 -0
  135. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/pyproject/reqs.py +0 -0
  136. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/revisions.py +0 -0
  137. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/__init__.py +0 -0
  138. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/bumpversion.py +0 -0
  139. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/execrss.py +0 -0
  140. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/exectime.py +0 -0
  141. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/importtrace.py +0 -0
  142. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/slowcat.py +0 -0
  143. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/scripts/tmpexec.py +0 -0
  144. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/secrets.py +0 -0
  145. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tokens.py +0 -0
  146. {omdev-0.0.0.dev147/omdev/pyproject → omdev-0.0.0.dev149/omdev/toml}/__init__.py +0 -0
  147. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/toml/parser.py +0 -0
  148. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/toml/writer.py +0 -0
  149. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/__init__.py +0 -0
  150. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/cloc.py +0 -0
  151. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/importscan.py +0 -0
  152. {omdev-0.0.0.dev147/omdev/tools/pawk → omdev-0.0.0.dev149/omdev/tools/json}/__init__.py +0 -0
  153. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/json/__main__.py +0 -0
  154. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/json/cli.py +0 -0
  155. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/json/formats.py +0 -0
  156. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/json/io.py +0 -0
  157. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/json/processing.py +0 -0
  158. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/json/rendering.py +0 -0
  159. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/mkrelimp.py +0 -0
  160. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/pawk/__main__.py +0 -0
  161. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/pawk/pawk.py +0 -0
  162. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/tools/qr.py +0 -0
  163. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev/wheelfile.py +0 -0
  164. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev.egg-info/dependency_links.txt +0 -0
  165. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev.egg-info/entry_points.txt +0 -0
  166. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/omdev.egg-info/top_level.txt +0 -0
  167. {omdev-0.0.0.dev147 → omdev-0.0.0.dev149}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omdev
3
- Version: 0.0.0.dev147
3
+ Version: 0.0.0.dev149
4
4
  Summary: omdev
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,7 +12,7 @@ Classifier: Operating System :: OS Independent
12
12
  Classifier: Operating System :: POSIX
13
13
  Requires-Python: >=3.12
14
14
  License-File: LICENSE
15
- Requires-Dist: omlish==0.0.0.dev147
15
+ Requires-Dist: omlish==0.0.0.dev149
16
16
  Provides-Extra: all
17
17
  Requires-Dist: black~=24.10; extra == "all"
18
18
  Requires-Dist: pycparser~=2.22; extra == "all"
@@ -107,6 +107,18 @@
107
107
  }
108
108
  }
109
109
  },
110
+ {
111
+ "module": ".manifests.__main__",
112
+ "attr": "_CLI_MODULE",
113
+ "file": "omdev/manifests/__main__.py",
114
+ "line": 4,
115
+ "value": {
116
+ "$.cli.types.CliModule": {
117
+ "cmd_name": "manifests",
118
+ "mod_name": "omdev.manifests.__main__"
119
+ }
120
+ }
121
+ },
110
122
  {
111
123
  "module": ".precheck.__main__",
112
124
  "attr": "_CLI_MODULE",
@@ -4,6 +4,7 @@ Conventions:
4
4
  - must import 'from' items for local modules
5
5
 
6
6
  TODO:
7
+ - !! check only importing lite code
7
8
  - !! strip manifests? or relegate them to a separate tiny module ala __main__.py?
8
9
  - # @omlish-no-amalg ? in cli.types? will strip stmt (more than 1 line) following @manifest, so shouldn't import
9
10
  - more sanity checks lol
@@ -6,7 +6,7 @@ import urllib.parse
6
6
  import urllib.request
7
7
 
8
8
  from omlish import __about__
9
- from omlish import argparse as ap
9
+ from omlish.argparse import all as ap
10
10
 
11
11
  from ..pip import get_root_dists
12
12
  from ..pip import lookup_latest_package_version
@@ -104,7 +104,7 @@ def upload_image(
104
104
 
105
105
 
106
106
  def _main() -> None:
107
- from omlish import argparse as ap
107
+ from omlish.argparse import all as ap
108
108
 
109
109
  class Cli(ap.Cli):
110
110
  @ap.command(
@@ -8,6 +8,7 @@ TODO:
8
8
  - colon sep provider name prefix - pyenv:3.12
9
9
  """
10
10
  import argparse
11
+ import asyncio
11
12
  import typing as ta
12
13
 
13
14
  from omlish.lite.check import check_not_none
@@ -20,20 +21,20 @@ from .resolvers import InterpResolver
20
21
  from .types import InterpSpecifier
21
22
 
22
23
 
23
- def _list_cmd(args) -> None:
24
+ async def _list_cmd(args) -> None:
24
25
  r = DEFAULT_INTERP_RESOLVER
25
26
  s = InterpSpecifier.parse(args.version)
26
- r.list(s)
27
+ await r.list(s)
27
28
 
28
29
 
29
- def _resolve_cmd(args) -> None:
30
+ async def _resolve_cmd(args) -> None:
30
31
  if args.provider:
31
32
  p = INTERP_PROVIDER_TYPES_BY_NAME[args.provider]()
32
33
  r = InterpResolver([(p.name, p)])
33
34
  else:
34
35
  r = DEFAULT_INTERP_RESOLVER
35
36
  s = InterpSpecifier.parse(args.version)
36
- print(check_not_none(r.resolve(s, install=bool(args.install))).exe)
37
+ print(check_not_none(await r.resolve(s, install=bool(args.install))).exe)
37
38
 
38
39
 
39
40
  def _build_parser() -> argparse.ArgumentParser:
@@ -56,7 +57,7 @@ def _build_parser() -> argparse.ArgumentParser:
56
57
  return parser
57
58
 
58
59
 
59
- def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
60
+ async def _async_main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
60
61
  check_runtime_version()
61
62
  configure_standard_logging()
62
63
 
@@ -65,7 +66,11 @@ def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
65
66
  if not getattr(args, 'func', None):
66
67
  parser.print_help()
67
68
  else:
68
- args.func(args)
69
+ await args.func(args)
70
+
71
+
72
+ def _main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
73
+ asyncio.run(_async_main(argv))
69
74
 
70
75
 
71
76
  if __name__ == '__main__':
@@ -5,8 +5,8 @@ import logging
5
5
  import sys
6
6
  import typing as ta
7
7
 
8
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_output
8
9
  from omlish.lite.logs import log
9
- from omlish.lite.subprocesses import subprocess_check_output
10
10
 
11
11
  from ..packaging.versions import Version
12
12
  from .types import InterpOpts
@@ -43,7 +43,6 @@ class InterpInspection:
43
43
 
44
44
 
45
45
  class InterpInspector:
46
-
47
46
  def __init__(self) -> None:
48
47
  super().__init__()
49
48
 
@@ -83,17 +82,17 @@ class InterpInspector:
83
82
  def running(cls) -> 'InterpInspection':
84
83
  return cls._build_inspection(sys.executable, eval(cls._INSPECTION_CODE)) # noqa
85
84
 
86
- def _inspect(self, exe: str) -> InterpInspection:
87
- output = subprocess_check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
85
+ async def _inspect(self, exe: str) -> InterpInspection:
86
+ output = await asyncio_subprocess_check_output(exe, '-c', f'print({self._INSPECTION_CODE})', quiet=True)
88
87
  return self._build_inspection(exe, output.decode())
89
88
 
90
- def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
89
+ async def inspect(self, exe: str) -> ta.Optional[InterpInspection]:
91
90
  try:
92
91
  return self._cache[exe]
93
92
  except KeyError:
94
93
  ret: ta.Optional[InterpInspection]
95
94
  try:
96
- ret = self._inspect(exe)
95
+ ret = await self._inspect(exe)
97
96
  except Exception as e: # noqa
98
97
  if log.isEnabledFor(logging.DEBUG):
99
98
  log.exception('Failed to inspect interp: %s', exe)
@@ -34,17 +34,17 @@ class InterpProvider(abc.ABC):
34
34
  setattr(cls, 'name', snake_case(cls.__name__[:-len(sfx)]))
35
35
 
36
36
  @abc.abstractmethod
37
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
37
+ def get_installed_versions(self, spec: InterpSpecifier) -> ta.Awaitable[ta.Sequence[InterpVersion]]:
38
38
  raise NotImplementedError
39
39
 
40
40
  @abc.abstractmethod
41
- def get_installed_version(self, version: InterpVersion) -> Interp:
41
+ def get_installed_version(self, version: InterpVersion) -> ta.Awaitable[Interp]:
42
42
  raise NotImplementedError
43
43
 
44
- def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
44
+ async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
45
45
  return []
46
46
 
47
- def install_version(self, version: InterpVersion) -> Interp:
47
+ async def install_version(self, version: InterpVersion) -> Interp:
48
48
  raise TypeError
49
49
 
50
50
 
@@ -56,10 +56,10 @@ class RunningInterpProvider(InterpProvider):
56
56
  def version(self) -> InterpVersion:
57
57
  return InterpInspector.running().iv
58
58
 
59
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
59
+ async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
60
60
  return [self.version()]
61
61
 
62
- def get_installed_version(self, version: InterpVersion) -> Interp:
62
+ async def get_installed_version(self, version: InterpVersion) -> Interp:
63
63
  if version != self.version():
64
64
  raise KeyError(version)
65
65
  return Interp(
@@ -18,12 +18,13 @@ import shutil
18
18
  import sys
19
19
  import typing as ta
20
20
 
21
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_call
22
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocess_check_output_str
23
+ from omlish.lite.asyncio.subprocesses import asyncio_subprocess_try_output
24
+ from omlish.lite.cached import async_cached_nullary
21
25
  from omlish.lite.cached import cached_nullary
22
26
  from omlish.lite.check import check_not_none
23
27
  from omlish.lite.logs import log
24
- from omlish.lite.subprocesses import subprocess_check_call
25
- from omlish.lite.subprocesses import subprocess_check_output_str
26
- from omlish.lite.subprocesses import subprocess_try_output
27
28
 
28
29
  from ..packaging.versions import InvalidVersion
29
30
  from ..packaging.versions import Version
@@ -40,7 +41,6 @@ from .types import InterpVersion
40
41
 
41
42
 
42
43
  class Pyenv:
43
-
44
44
  def __init__(
45
45
  self,
46
46
  *,
@@ -53,13 +53,13 @@ class Pyenv:
53
53
 
54
54
  self._root_kw = root
55
55
 
56
- @cached_nullary
57
- def root(self) -> ta.Optional[str]:
56
+ @async_cached_nullary
57
+ async def root(self) -> ta.Optional[str]:
58
58
  if self._root_kw is not None:
59
59
  return self._root_kw
60
60
 
61
61
  if shutil.which('pyenv'):
62
- return subprocess_check_output_str('pyenv', 'root')
62
+ return await asyncio_subprocess_check_output_str('pyenv', 'root')
63
63
 
64
64
  d = os.path.expanduser('~/.pyenv')
65
65
  if os.path.isdir(d) and os.path.isfile(os.path.join(d, 'bin', 'pyenv')):
@@ -67,12 +67,12 @@ class Pyenv:
67
67
 
68
68
  return None
69
69
 
70
- @cached_nullary
71
- def exe(self) -> str:
72
- return os.path.join(check_not_none(self.root()), 'bin', 'pyenv')
70
+ @async_cached_nullary
71
+ async def exe(self) -> str:
72
+ return os.path.join(check_not_none(await self.root()), 'bin', 'pyenv')
73
73
 
74
- def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
75
- if (root := self.root()) is None:
74
+ async def version_exes(self) -> ta.List[ta.Tuple[str, str]]:
75
+ if (root := await self.root()) is None:
76
76
  return []
77
77
  ret = []
78
78
  vp = os.path.join(root, 'versions')
@@ -84,11 +84,11 @@ class Pyenv:
84
84
  ret.append((dn, ep))
85
85
  return ret
86
86
 
87
- def installable_versions(self) -> ta.List[str]:
88
- if self.root() is None:
87
+ async def installable_versions(self) -> ta.List[str]:
88
+ if await self.root() is None:
89
89
  return []
90
90
  ret = []
91
- s = subprocess_check_output_str(self.exe(), 'install', '--list')
91
+ s = await asyncio_subprocess_check_output_str(await self.exe(), 'install', '--list')
92
92
  for l in s.splitlines():
93
93
  if not l.startswith(' '):
94
94
  continue
@@ -98,12 +98,12 @@ class Pyenv:
98
98
  ret.append(l)
99
99
  return ret
100
100
 
101
- def update(self) -> bool:
102
- if (root := self.root()) is None:
101
+ async def update(self) -> bool:
102
+ if (root := await self.root()) is None:
103
103
  return False
104
104
  if not os.path.isdir(os.path.join(root, '.git')):
105
105
  return False
106
- subprocess_check_call('git', 'pull', cwd=root)
106
+ await asyncio_subprocess_check_call('git', 'pull', cwd=root)
107
107
  return True
108
108
 
109
109
 
@@ -164,17 +164,16 @@ THREADED_PYENV_INSTALL_OPTS = PyenvInstallOpts(conf_opts=['--disable-gil'])
164
164
 
165
165
  class PyenvInstallOptsProvider(abc.ABC):
166
166
  @abc.abstractmethod
167
- def opts(self) -> PyenvInstallOpts:
167
+ def opts(self) -> ta.Awaitable[PyenvInstallOpts]:
168
168
  raise NotImplementedError
169
169
 
170
170
 
171
171
  class LinuxPyenvInstallOpts(PyenvInstallOptsProvider):
172
- def opts(self) -> PyenvInstallOpts:
172
+ async def opts(self) -> PyenvInstallOpts:
173
173
  return PyenvInstallOpts()
174
174
 
175
175
 
176
176
  class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
177
-
178
177
  @cached_nullary
179
178
  def framework_opts(self) -> PyenvInstallOpts:
180
179
  return PyenvInstallOpts(conf_opts=['--enable-framework'])
@@ -190,12 +189,12 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
190
189
  'zlib',
191
190
  ]
192
191
 
193
- @cached_nullary
194
- def brew_deps_opts(self) -> PyenvInstallOpts:
192
+ @async_cached_nullary
193
+ async def brew_deps_opts(self) -> PyenvInstallOpts:
195
194
  cflags = []
196
195
  ldflags = []
197
196
  for dep in self.BREW_DEPS:
198
- dep_prefix = subprocess_check_output_str('brew', '--prefix', dep)
197
+ dep_prefix = await asyncio_subprocess_check_output_str('brew', '--prefix', dep)
199
198
  cflags.append(f'-I{dep_prefix}/include')
200
199
  ldflags.append(f'-L{dep_prefix}/lib')
201
200
  return PyenvInstallOpts(
@@ -203,13 +202,13 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
203
202
  ldflags=ldflags,
204
203
  )
205
204
 
206
- @cached_nullary
207
- def brew_tcl_opts(self) -> PyenvInstallOpts:
208
- if subprocess_try_output('brew', '--prefix', 'tcl-tk') is None:
205
+ @async_cached_nullary
206
+ async def brew_tcl_opts(self) -> PyenvInstallOpts:
207
+ if await asyncio_subprocess_try_output('brew', '--prefix', 'tcl-tk') is None:
209
208
  return PyenvInstallOpts()
210
209
 
211
- tcl_tk_prefix = subprocess_check_output_str('brew', '--prefix', 'tcl-tk')
212
- tcl_tk_ver_str = subprocess_check_output_str('brew', 'ls', '--versions', 'tcl-tk')
210
+ tcl_tk_prefix = await asyncio_subprocess_check_output_str('brew', '--prefix', 'tcl-tk')
211
+ tcl_tk_ver_str = await asyncio_subprocess_check_output_str('brew', 'ls', '--versions', 'tcl-tk')
213
212
  tcl_tk_ver = '.'.join(tcl_tk_ver_str.split()[1].split('.')[:2])
214
213
 
215
214
  return PyenvInstallOpts(conf_opts=[
@@ -224,11 +223,11 @@ class DarwinPyenvInstallOpts(PyenvInstallOptsProvider):
224
223
  # pkg_config_path += ':' + os.environ['PKG_CONFIG_PATH']
225
224
  # return PyenvInstallOpts(env={'PKG_CONFIG_PATH': pkg_config_path})
226
225
 
227
- def opts(self) -> PyenvInstallOpts:
226
+ async def opts(self) -> PyenvInstallOpts:
228
227
  return PyenvInstallOpts().merge(
229
228
  self.framework_opts(),
230
- self.brew_deps_opts(),
231
- self.brew_tcl_opts(),
229
+ await self.brew_deps_opts(),
230
+ await self.brew_tcl_opts(),
232
231
  # self.brew_ssl_opts(),
233
232
  )
234
233
 
@@ -260,20 +259,8 @@ class PyenvVersionInstaller:
260
259
  ) -> None:
261
260
  super().__init__()
262
261
 
263
- if no_default_opts:
264
- if opts is None:
265
- opts = PyenvInstallOpts()
266
- else:
267
- lst = [opts if opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
268
- if interp_opts.debug:
269
- lst.append(DEBUG_PYENV_INSTALL_OPTS)
270
- if interp_opts.threaded:
271
- lst.append(THREADED_PYENV_INSTALL_OPTS)
272
- lst.append(PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
273
- opts = PyenvInstallOpts().merge(*lst)
274
-
275
262
  self._version = version
276
- self._opts = opts
263
+ self._given_opts = opts
277
264
  self._interp_opts = interp_opts
278
265
  self._given_install_name = install_name
279
266
 
@@ -284,9 +271,21 @@ class PyenvVersionInstaller:
284
271
  def version(self) -> str:
285
272
  return self._version
286
273
 
287
- @property
288
- def opts(self) -> PyenvInstallOpts:
289
- return self._opts
274
+ @async_cached_nullary
275
+ async def opts(self) -> PyenvInstallOpts:
276
+ opts = self._given_opts
277
+ if self._no_default_opts:
278
+ if opts is None:
279
+ opts = PyenvInstallOpts()
280
+ else:
281
+ lst = [self._given_opts if self._given_opts is not None else DEFAULT_PYENV_INSTALL_OPTS]
282
+ if self._interp_opts.debug:
283
+ lst.append(DEBUG_PYENV_INSTALL_OPTS)
284
+ if self._interp_opts.threaded:
285
+ lst.append(THREADED_PYENV_INSTALL_OPTS)
286
+ lst.append(await PLATFORM_PYENV_INSTALL_OPTS[sys.platform].opts())
287
+ opts = PyenvInstallOpts().merge(*lst)
288
+ return opts
290
289
 
291
290
  @cached_nullary
292
291
  def install_name(self) -> str:
@@ -294,17 +293,18 @@ class PyenvVersionInstaller:
294
293
  return self._given_install_name
295
294
  return self._version + ('-debug' if self._interp_opts.debug else '')
296
295
 
297
- @cached_nullary
298
- def install_dir(self) -> str:
299
- return str(os.path.join(check_not_none(self._pyenv.root()), 'versions', self.install_name()))
296
+ @async_cached_nullary
297
+ async def install_dir(self) -> str:
298
+ return str(os.path.join(check_not_none(await self._pyenv.root()), 'versions', self.install_name()))
300
299
 
301
- @cached_nullary
302
- def install(self) -> str:
303
- env = {**os.environ, **self._opts.env}
300
+ @async_cached_nullary
301
+ async def install(self) -> str:
302
+ opts = await self.opts()
303
+ env = {**os.environ, **opts.env}
304
304
  for k, l in [
305
- ('CFLAGS', self._opts.cflags),
306
- ('LDFLAGS', self._opts.ldflags),
307
- ('PYTHON_CONFIGURE_OPTS', self._opts.conf_opts),
305
+ ('CFLAGS', opts.cflags),
306
+ ('LDFLAGS', opts.ldflags),
307
+ ('PYTHON_CONFIGURE_OPTS', opts.conf_opts),
308
308
  ]:
309
309
  v = ' '.join(l)
310
310
  if k in os.environ:
@@ -312,13 +312,13 @@ class PyenvVersionInstaller:
312
312
  env[k] = v
313
313
 
314
314
  conf_args = [
315
- *self._opts.opts,
315
+ *opts.opts,
316
316
  self._version,
317
317
  ]
318
318
 
319
319
  if self._given_install_name is not None:
320
320
  full_args = [
321
- os.path.join(check_not_none(self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'),
321
+ os.path.join(check_not_none(await self._pyenv.root()), 'plugins', 'python-build', 'bin', 'python-build'), # noqa
322
322
  *conf_args,
323
323
  self.install_dir(),
324
324
  ]
@@ -329,12 +329,12 @@ class PyenvVersionInstaller:
329
329
  *conf_args,
330
330
  ]
331
331
 
332
- subprocess_check_call(
332
+ await asyncio_subprocess_check_call(
333
333
  *full_args,
334
334
  env=env,
335
335
  )
336
336
 
337
- exe = os.path.join(self.install_dir(), 'bin', 'python')
337
+ exe = os.path.join(await self.install_dir(), 'bin', 'python')
338
338
  if not os.path.isfile(exe):
339
339
  raise RuntimeError(f'Interpreter not found: {exe}')
340
340
  return exe
@@ -344,7 +344,6 @@ class PyenvVersionInstaller:
344
344
 
345
345
 
346
346
  class PyenvInterpProvider(InterpProvider):
347
-
348
347
  def __init__(
349
348
  self,
350
349
  pyenv: Pyenv = Pyenv(),
@@ -387,11 +386,11 @@ class PyenvInterpProvider(InterpProvider):
387
386
  exe: str
388
387
  version: InterpVersion
389
388
 
390
- def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
389
+ async def _make_installed(self, vn: str, ep: str) -> ta.Optional[Installed]:
391
390
  iv: ta.Optional[InterpVersion]
392
391
  if self._inspect:
393
392
  try:
394
- iv = check_not_none(self._inspector.inspect(ep)).iv
393
+ iv = check_not_none(await self._inspector.inspect(ep)).iv
395
394
  except Exception as e: # noqa
396
395
  return None
397
396
  else:
@@ -404,10 +403,10 @@ class PyenvInterpProvider(InterpProvider):
404
403
  version=iv,
405
404
  )
406
405
 
407
- def installed(self) -> ta.Sequence[Installed]:
406
+ async def installed(self) -> ta.Sequence[Installed]:
408
407
  ret: ta.List[PyenvInterpProvider.Installed] = []
409
- for vn, ep in self._pyenv.version_exes():
410
- if (i := self._make_installed(vn, ep)) is None:
408
+ for vn, ep in await self._pyenv.version_exes():
409
+ if (i := await self._make_installed(vn, ep)) is None:
411
410
  log.debug('Invalid pyenv version: %s', vn)
412
411
  continue
413
412
  ret.append(i)
@@ -415,11 +414,11 @@ class PyenvInterpProvider(InterpProvider):
415
414
 
416
415
  #
417
416
 
418
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
419
- return [i.version for i in self.installed()]
417
+ async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
418
+ return [i.version for i in await self.installed()]
420
419
 
421
- def get_installed_version(self, version: InterpVersion) -> Interp:
422
- for i in self.installed():
420
+ async def get_installed_version(self, version: InterpVersion) -> Interp:
421
+ for i in await self.installed():
423
422
  if i.version == version:
424
423
  return Interp(
425
424
  exe=i.exe,
@@ -429,10 +428,10 @@ class PyenvInterpProvider(InterpProvider):
429
428
 
430
429
  #
431
430
 
432
- def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
431
+ async def _get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
433
432
  lst = []
434
433
 
435
- for vs in self._pyenv.installable_versions():
434
+ for vs in await self._pyenv.installable_versions():
436
435
  if (iv := self.guess_version(vs)) is None:
437
436
  continue
438
437
  if iv.opts.debug:
@@ -442,16 +441,16 @@ class PyenvInterpProvider(InterpProvider):
442
441
 
443
442
  return lst
444
443
 
445
- def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
446
- lst = self._get_installable_versions(spec)
444
+ async def get_installable_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
445
+ lst = await self._get_installable_versions(spec)
447
446
 
448
447
  if self._try_update and not any(v in spec for v in lst):
449
448
  if self._pyenv.update():
450
- lst = self._get_installable_versions(spec)
449
+ lst = await self._get_installable_versions(spec)
451
450
 
452
451
  return lst
453
452
 
454
- def install_version(self, version: InterpVersion) -> Interp:
453
+ async def install_version(self, version: InterpVersion) -> Interp:
455
454
  inst_version = str(version.version)
456
455
  inst_opts = version.opts
457
456
  if inst_opts.threaded:
@@ -463,5 +462,5 @@ class PyenvInterpProvider(InterpProvider):
463
462
  interp_opts=inst_opts,
464
463
  )
465
464
 
466
- exe = installer.install()
465
+ exe = await installer.install()
467
466
  return Interp(exe, version)
@@ -25,13 +25,14 @@ class InterpResolver:
25
25
  providers: ta.Sequence[ta.Tuple[str, InterpProvider]],
26
26
  ) -> None:
27
27
  super().__init__()
28
+
28
29
  self._providers: ta.Mapping[str, InterpProvider] = collections.OrderedDict(providers)
29
30
 
30
- def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
31
+ async def _resolve_installed(self, spec: InterpSpecifier) -> ta.Optional[ta.Tuple[InterpProvider, InterpVersion]]:
31
32
  lst = [
32
33
  (i, si)
33
34
  for i, p in enumerate(self._providers.values())
34
- for si in p.get_installed_versions(spec)
35
+ for si in await p.get_installed_versions(spec)
35
36
  if spec.contains(si)
36
37
  ]
37
38
 
@@ -43,16 +44,16 @@ class InterpResolver:
43
44
  bp = list(self._providers.values())[bi]
44
45
  return (bp, bv)
45
46
 
46
- def resolve(
47
+ async def resolve(
47
48
  self,
48
49
  spec: InterpSpecifier,
49
50
  *,
50
51
  install: bool = False,
51
52
  ) -> ta.Optional[Interp]:
52
- tup = self._resolve_installed(spec)
53
+ tup = await self._resolve_installed(spec)
53
54
  if tup is not None:
54
55
  bp, bv = tup
55
- return bp.get_installed_version(bv)
56
+ return await bp.get_installed_version(bv)
56
57
 
57
58
  if not install:
58
59
  return None
@@ -60,21 +61,21 @@ class InterpResolver:
60
61
  tp = list(self._providers.values())[0] # noqa
61
62
 
62
63
  sv = sorted(
63
- [s for s in tp.get_installable_versions(spec) if s in spec],
64
+ [s for s in await tp.get_installable_versions(spec) if s in spec],
64
65
  key=lambda s: s.version,
65
66
  )
66
67
  if not sv:
67
68
  return None
68
69
 
69
70
  bv = sv[-1]
70
- return tp.install_version(bv)
71
+ return await tp.install_version(bv)
71
72
 
72
- def list(self, spec: InterpSpecifier) -> None:
73
+ async def list(self, spec: InterpSpecifier) -> None:
73
74
  print('installed:')
74
75
  for n, p in self._providers.items():
75
76
  lst = [
76
77
  si
77
- for si in p.get_installed_versions(spec)
78
+ for si in await p.get_installed_versions(spec)
78
79
  if spec.contains(si)
79
80
  ]
80
81
  if lst:
@@ -88,7 +89,7 @@ class InterpResolver:
88
89
  for n, p in self._providers.items():
89
90
  lst = [
90
91
  si
91
- for si in p.get_installable_versions(spec)
92
+ for si in await p.get_installable_versions(spec)
92
93
  if spec.contains(si)
93
94
  ]
94
95
  if lst:
@@ -87,7 +87,7 @@ class SystemInterpProvider(InterpProvider):
87
87
 
88
88
  #
89
89
 
90
- def get_exe_version(self, exe: str) -> ta.Optional[InterpVersion]:
90
+ async def get_exe_version(self, exe: str) -> ta.Optional[InterpVersion]:
91
91
  if not self.inspect:
92
92
  s = os.path.basename(exe)
93
93
  if s.startswith('python'):
@@ -97,13 +97,13 @@ class SystemInterpProvider(InterpProvider):
97
97
  return InterpVersion.parse(s)
98
98
  except InvalidVersion:
99
99
  pass
100
- ii = self.inspector.inspect(exe)
100
+ ii = await self.inspector.inspect(exe)
101
101
  return ii.iv if ii is not None else None
102
102
 
103
- def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
103
+ async def exe_versions(self) -> ta.Sequence[ta.Tuple[str, InterpVersion]]:
104
104
  lst = []
105
105
  for e in self.exes():
106
- if (ev := self.get_exe_version(e)) is None:
106
+ if (ev := await self.get_exe_version(e)) is None:
107
107
  log.debug('Invalid system version: %s', e)
108
108
  continue
109
109
  lst.append((e, ev))
@@ -111,11 +111,11 @@ class SystemInterpProvider(InterpProvider):
111
111
 
112
112
  #
113
113
 
114
- def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
115
- return [ev for e, ev in self.exe_versions()]
114
+ async def get_installed_versions(self, spec: InterpSpecifier) -> ta.Sequence[InterpVersion]:
115
+ return [ev for e, ev in await self.exe_versions()]
116
116
 
117
- def get_installed_version(self, version: InterpVersion) -> Interp:
118
- for e, ev in self.exe_versions():
117
+ async def get_installed_version(self, version: InterpVersion) -> Interp:
118
+ for e, ev in await self.exe_versions():
119
119
  if ev != version:
120
120
  continue
121
121
  return Interp(
@@ -77,6 +77,8 @@ class InterpSpecifier:
77
77
  s, o = InterpOpts.parse_suffix(s)
78
78
  if not any(s.startswith(o) for o in Specifier.OPERATORS):
79
79
  s = '~=' + s
80
+ if s.count('.') < 2:
81
+ s += '.0'
80
82
  return cls(
81
83
  specifier=Specifier(s),
82
84
  opts=o,