omdev 0.0.0.dev157__py3-none-any.whl → 0.0.0.dev159__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.
Potentially problematic release.
This version of omdev might be problematic. Click here for more details.
- omdev/amalg/amalg.py +4 -4
- omdev/cache/data/cache.py +2 -2
- omdev/cache/data/manifests.py +1 -1
- omdev/cexts/cmake.py +1 -1
- omdev/cexts/scan.py +1 -1
- omdev/git/__init__.py +0 -0
- omdev/git/revisions.py +50 -0
- omdev/{git.py → git/status.py} +1 -112
- omdev/git/subtrees.py +100 -0
- omdev/interp/cli.py +3 -3
- omdev/interp/inspect.py +1 -1
- omdev/interp/pyenv.py +1 -1
- omdev/manifests/main.py +1 -1
- omdev/precheck/lite.py +1 -1
- omdev/precheck/main.py +1 -1
- omdev/pyproject/cli.py +4 -4
- omdev/pyproject/pkg.py +1 -1
- omdev/pyproject/venvs.py +1 -1
- omdev/revisions.py +2 -2
- omdev/scripts/interp.py +370 -293
- omdev/scripts/pyproject.py +497 -775
- omdev/tools/docker.py +1 -1
- omdev/tools/git.py +3 -3
- omdev/tools/mkrelimp.py +1 -1
- omdev/tools/sqlrepl.py +1 -1
- {omdev-0.0.0.dev157.dist-info → omdev-0.0.0.dev159.dist-info}/METADATA +2 -2
- {omdev-0.0.0.dev157.dist-info → omdev-0.0.0.dev159.dist-info}/RECORD +31 -28
- {omdev-0.0.0.dev157.dist-info → omdev-0.0.0.dev159.dist-info}/LICENSE +0 -0
- {omdev-0.0.0.dev157.dist-info → omdev-0.0.0.dev159.dist-info}/WHEEL +0 -0
- {omdev-0.0.0.dev157.dist-info → omdev-0.0.0.dev159.dist-info}/entry_points.txt +0 -0
- {omdev-0.0.0.dev157.dist-info → omdev-0.0.0.dev159.dist-info}/top_level.txt +0 -0
omdev/scripts/interp.py
CHANGED
|
@@ -75,7 +75,7 @@ UnparsedVersion = ta.Union['Version', str]
|
|
|
75
75
|
UnparsedVersionVar = ta.TypeVar('UnparsedVersionVar', bound=UnparsedVersion)
|
|
76
76
|
CallableVersionOperator = ta.Callable[['Version', str], bool]
|
|
77
77
|
|
|
78
|
-
# ../../omlish/
|
|
78
|
+
# ../../omlish/subprocesses.py
|
|
79
79
|
SubprocessChannelOption = ta.Literal['pipe', 'stdout', 'devnull'] # ta.TypeAlias
|
|
80
80
|
|
|
81
81
|
|
|
@@ -1036,6 +1036,13 @@ json_dump_compact: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON
|
|
|
1036
1036
|
json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_COMPACT_KWARGS)
|
|
1037
1037
|
|
|
1038
1038
|
|
|
1039
|
+
########################################
|
|
1040
|
+
# ../../../omlish/lite/logs.py
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
log = logging.getLogger(__name__)
|
|
1044
|
+
|
|
1045
|
+
|
|
1039
1046
|
########################################
|
|
1040
1047
|
# ../../../omlish/lite/reflect.py
|
|
1041
1048
|
|
|
@@ -1158,6 +1165,116 @@ def format_num_bytes(num_bytes: int) -> str:
|
|
|
1158
1165
|
return f'{num_bytes / 1024 ** (len(FORMAT_NUM_BYTES_SUFFIXES) - 1):.2f}{FORMAT_NUM_BYTES_SUFFIXES[-1]}'
|
|
1159
1166
|
|
|
1160
1167
|
|
|
1168
|
+
########################################
|
|
1169
|
+
# ../../../omlish/logs/filters.py
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
class TidLogFilter(logging.Filter):
|
|
1173
|
+
def filter(self, record):
|
|
1174
|
+
record.tid = threading.get_native_id()
|
|
1175
|
+
return True
|
|
1176
|
+
|
|
1177
|
+
|
|
1178
|
+
########################################
|
|
1179
|
+
# ../../../omlish/logs/proxy.py
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
class ProxyLogFilterer(logging.Filterer):
|
|
1183
|
+
def __init__(self, underlying: logging.Filterer) -> None: # noqa
|
|
1184
|
+
self._underlying = underlying
|
|
1185
|
+
|
|
1186
|
+
@property
|
|
1187
|
+
def underlying(self) -> logging.Filterer:
|
|
1188
|
+
return self._underlying
|
|
1189
|
+
|
|
1190
|
+
@property
|
|
1191
|
+
def filters(self):
|
|
1192
|
+
return self._underlying.filters
|
|
1193
|
+
|
|
1194
|
+
@filters.setter
|
|
1195
|
+
def filters(self, filters):
|
|
1196
|
+
self._underlying.filters = filters
|
|
1197
|
+
|
|
1198
|
+
def addFilter(self, filter): # noqa
|
|
1199
|
+
self._underlying.addFilter(filter)
|
|
1200
|
+
|
|
1201
|
+
def removeFilter(self, filter): # noqa
|
|
1202
|
+
self._underlying.removeFilter(filter)
|
|
1203
|
+
|
|
1204
|
+
def filter(self, record):
|
|
1205
|
+
return self._underlying.filter(record)
|
|
1206
|
+
|
|
1207
|
+
|
|
1208
|
+
class ProxyLogHandler(ProxyLogFilterer, logging.Handler):
|
|
1209
|
+
def __init__(self, underlying: logging.Handler) -> None: # noqa
|
|
1210
|
+
ProxyLogFilterer.__init__(self, underlying)
|
|
1211
|
+
|
|
1212
|
+
_underlying: logging.Handler
|
|
1213
|
+
|
|
1214
|
+
@property
|
|
1215
|
+
def underlying(self) -> logging.Handler:
|
|
1216
|
+
return self._underlying
|
|
1217
|
+
|
|
1218
|
+
def get_name(self):
|
|
1219
|
+
return self._underlying.get_name()
|
|
1220
|
+
|
|
1221
|
+
def set_name(self, name):
|
|
1222
|
+
self._underlying.set_name(name)
|
|
1223
|
+
|
|
1224
|
+
@property
|
|
1225
|
+
def name(self):
|
|
1226
|
+
return self._underlying.name
|
|
1227
|
+
|
|
1228
|
+
@property
|
|
1229
|
+
def level(self):
|
|
1230
|
+
return self._underlying.level
|
|
1231
|
+
|
|
1232
|
+
@level.setter
|
|
1233
|
+
def level(self, level):
|
|
1234
|
+
self._underlying.level = level
|
|
1235
|
+
|
|
1236
|
+
@property
|
|
1237
|
+
def formatter(self):
|
|
1238
|
+
return self._underlying.formatter
|
|
1239
|
+
|
|
1240
|
+
@formatter.setter
|
|
1241
|
+
def formatter(self, formatter):
|
|
1242
|
+
self._underlying.formatter = formatter
|
|
1243
|
+
|
|
1244
|
+
def createLock(self):
|
|
1245
|
+
self._underlying.createLock()
|
|
1246
|
+
|
|
1247
|
+
def acquire(self):
|
|
1248
|
+
self._underlying.acquire()
|
|
1249
|
+
|
|
1250
|
+
def release(self):
|
|
1251
|
+
self._underlying.release()
|
|
1252
|
+
|
|
1253
|
+
def setLevel(self, level):
|
|
1254
|
+
self._underlying.setLevel(level)
|
|
1255
|
+
|
|
1256
|
+
def format(self, record):
|
|
1257
|
+
return self._underlying.format(record)
|
|
1258
|
+
|
|
1259
|
+
def emit(self, record):
|
|
1260
|
+
self._underlying.emit(record)
|
|
1261
|
+
|
|
1262
|
+
def handle(self, record):
|
|
1263
|
+
return self._underlying.handle(record)
|
|
1264
|
+
|
|
1265
|
+
def setFormatter(self, fmt):
|
|
1266
|
+
self._underlying.setFormatter(fmt)
|
|
1267
|
+
|
|
1268
|
+
def flush(self):
|
|
1269
|
+
self._underlying.flush()
|
|
1270
|
+
|
|
1271
|
+
def close(self):
|
|
1272
|
+
self._underlying.close()
|
|
1273
|
+
|
|
1274
|
+
def handleError(self, record):
|
|
1275
|
+
self._underlying.handleError(record)
|
|
1276
|
+
|
|
1277
|
+
|
|
1161
1278
|
########################################
|
|
1162
1279
|
# ../../packaging/specifiers.py
|
|
1163
1280
|
# Copyright (c) Donald Stufft and individual contributors.
|
|
@@ -1681,32 +1798,31 @@ class SpecifierSet(BaseSpecifier):
|
|
|
1681
1798
|
|
|
1682
1799
|
|
|
1683
1800
|
########################################
|
|
1684
|
-
# ../../../omlish/lite/
|
|
1685
|
-
"""
|
|
1686
|
-
TODO:
|
|
1687
|
-
- translate json keys
|
|
1688
|
-
- debug
|
|
1689
|
-
"""
|
|
1690
|
-
|
|
1801
|
+
# ../../../omlish/lite/runtime.py
|
|
1691
1802
|
|
|
1692
|
-
log = logging.getLogger(__name__)
|
|
1693
1803
|
|
|
1804
|
+
@cached_nullary
|
|
1805
|
+
def is_debugger_attached() -> bool:
|
|
1806
|
+
return any(frame[1].endswith('pydevd.py') for frame in inspect.stack())
|
|
1694
1807
|
|
|
1695
|
-
##
|
|
1696
1808
|
|
|
1809
|
+
LITE_REQUIRED_PYTHON_VERSION = (3, 8)
|
|
1697
1810
|
|
|
1698
|
-
class TidLogFilter(logging.Filter):
|
|
1699
1811
|
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1812
|
+
def check_lite_runtime_version() -> None:
|
|
1813
|
+
if sys.version_info < LITE_REQUIRED_PYTHON_VERSION:
|
|
1814
|
+
raise OSError(f'Requires python {LITE_REQUIRED_PYTHON_VERSION}, got {sys.version_info} from {sys.executable}') # noqa
|
|
1703
1815
|
|
|
1704
1816
|
|
|
1705
|
-
|
|
1817
|
+
########################################
|
|
1818
|
+
# ../../../omlish/logs/json.py
|
|
1819
|
+
"""
|
|
1820
|
+
TODO:
|
|
1821
|
+
- translate json keys
|
|
1822
|
+
"""
|
|
1706
1823
|
|
|
1707
1824
|
|
|
1708
1825
|
class JsonLogFormatter(logging.Formatter):
|
|
1709
|
-
|
|
1710
1826
|
KEYS: ta.Mapping[str, bool] = {
|
|
1711
1827
|
'name': False,
|
|
1712
1828
|
'msg': False,
|
|
@@ -1730,6 +1846,18 @@ class JsonLogFormatter(logging.Formatter):
|
|
|
1730
1846
|
'process': False,
|
|
1731
1847
|
}
|
|
1732
1848
|
|
|
1849
|
+
def __init__(
|
|
1850
|
+
self,
|
|
1851
|
+
*args: ta.Any,
|
|
1852
|
+
json_dumps: ta.Optional[ta.Callable[[ta.Any], str]] = None,
|
|
1853
|
+
**kwargs: ta.Any,
|
|
1854
|
+
) -> None:
|
|
1855
|
+
super().__init__(*args, **kwargs)
|
|
1856
|
+
|
|
1857
|
+
if json_dumps is None:
|
|
1858
|
+
json_dumps = json_dumps_compact
|
|
1859
|
+
self._json_dumps = json_dumps
|
|
1860
|
+
|
|
1733
1861
|
def format(self, record: logging.LogRecord) -> str:
|
|
1734
1862
|
dct = {
|
|
1735
1863
|
k: v
|
|
@@ -1737,7 +1865,111 @@ class JsonLogFormatter(logging.Formatter):
|
|
|
1737
1865
|
for v in [getattr(record, k)]
|
|
1738
1866
|
if not (o and v is None)
|
|
1739
1867
|
}
|
|
1740
|
-
return
|
|
1868
|
+
return self._json_dumps(dct)
|
|
1869
|
+
|
|
1870
|
+
|
|
1871
|
+
########################################
|
|
1872
|
+
# ../types.py
|
|
1873
|
+
|
|
1874
|
+
|
|
1875
|
+
# See https://peps.python.org/pep-3149/
|
|
1876
|
+
INTERP_OPT_GLYPHS_BY_ATTR: ta.Mapping[str, str] = collections.OrderedDict([
|
|
1877
|
+
('debug', 'd'),
|
|
1878
|
+
('threaded', 't'),
|
|
1879
|
+
])
|
|
1880
|
+
|
|
1881
|
+
INTERP_OPT_ATTRS_BY_GLYPH: ta.Mapping[str, str] = collections.OrderedDict(
|
|
1882
|
+
(g, a) for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items()
|
|
1883
|
+
)
|
|
1884
|
+
|
|
1885
|
+
|
|
1886
|
+
@dc.dataclass(frozen=True)
|
|
1887
|
+
class InterpOpts:
|
|
1888
|
+
threaded: bool = False
|
|
1889
|
+
debug: bool = False
|
|
1890
|
+
|
|
1891
|
+
def __str__(self) -> str:
|
|
1892
|
+
return ''.join(g for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items() if getattr(self, a))
|
|
1893
|
+
|
|
1894
|
+
@classmethod
|
|
1895
|
+
def parse(cls, s: str) -> 'InterpOpts':
|
|
1896
|
+
return cls(**{INTERP_OPT_ATTRS_BY_GLYPH[g]: True for g in s})
|
|
1897
|
+
|
|
1898
|
+
@classmethod
|
|
1899
|
+
def parse_suffix(cls, s: str) -> ta.Tuple[str, 'InterpOpts']:
|
|
1900
|
+
kw = {}
|
|
1901
|
+
while s and (a := INTERP_OPT_ATTRS_BY_GLYPH.get(s[-1])):
|
|
1902
|
+
s, kw[a] = s[:-1], True
|
|
1903
|
+
return s, cls(**kw)
|
|
1904
|
+
|
|
1905
|
+
|
|
1906
|
+
@dc.dataclass(frozen=True)
|
|
1907
|
+
class InterpVersion:
|
|
1908
|
+
version: Version
|
|
1909
|
+
opts: InterpOpts
|
|
1910
|
+
|
|
1911
|
+
def __str__(self) -> str:
|
|
1912
|
+
return str(self.version) + str(self.opts)
|
|
1913
|
+
|
|
1914
|
+
@classmethod
|
|
1915
|
+
def parse(cls, s: str) -> 'InterpVersion':
|
|
1916
|
+
s, o = InterpOpts.parse_suffix(s)
|
|
1917
|
+
v = Version(s)
|
|
1918
|
+
return cls(
|
|
1919
|
+
version=v,
|
|
1920
|
+
opts=o,
|
|
1921
|
+
)
|
|
1922
|
+
|
|
1923
|
+
@classmethod
|
|
1924
|
+
def try_parse(cls, s: str) -> ta.Optional['InterpVersion']:
|
|
1925
|
+
try:
|
|
1926
|
+
return cls.parse(s)
|
|
1927
|
+
except (KeyError, InvalidVersion):
|
|
1928
|
+
return None
|
|
1929
|
+
|
|
1930
|
+
|
|
1931
|
+
@dc.dataclass(frozen=True)
|
|
1932
|
+
class InterpSpecifier:
|
|
1933
|
+
specifier: Specifier
|
|
1934
|
+
opts: InterpOpts
|
|
1935
|
+
|
|
1936
|
+
def __str__(self) -> str:
|
|
1937
|
+
return str(self.specifier) + str(self.opts)
|
|
1938
|
+
|
|
1939
|
+
@classmethod
|
|
1940
|
+
def parse(cls, s: str) -> 'InterpSpecifier':
|
|
1941
|
+
s, o = InterpOpts.parse_suffix(s)
|
|
1942
|
+
if not any(s.startswith(o) for o in Specifier.OPERATORS):
|
|
1943
|
+
s = '~=' + s
|
|
1944
|
+
if s.count('.') < 2:
|
|
1945
|
+
s += '.0'
|
|
1946
|
+
return cls(
|
|
1947
|
+
specifier=Specifier(s),
|
|
1948
|
+
opts=o,
|
|
1949
|
+
)
|
|
1950
|
+
|
|
1951
|
+
def contains(self, iv: InterpVersion) -> bool:
|
|
1952
|
+
return self.specifier.contains(iv.version) and self.opts == iv.opts
|
|
1953
|
+
|
|
1954
|
+
def __contains__(self, iv: InterpVersion) -> bool:
|
|
1955
|
+
return self.contains(iv)
|
|
1956
|
+
|
|
1957
|
+
|
|
1958
|
+
@dc.dataclass(frozen=True)
|
|
1959
|
+
class Interp:
|
|
1960
|
+
exe: str
|
|
1961
|
+
version: InterpVersion
|
|
1962
|
+
|
|
1963
|
+
|
|
1964
|
+
########################################
|
|
1965
|
+
# ../../../omlish/logs/standard.py
|
|
1966
|
+
"""
|
|
1967
|
+
TODO:
|
|
1968
|
+
- structured
|
|
1969
|
+
- prefixed
|
|
1970
|
+
- debug
|
|
1971
|
+
- optional noisy? noisy will never be lite - some kinda configure_standard callback mechanism?
|
|
1972
|
+
"""
|
|
1741
1973
|
|
|
1742
1974
|
|
|
1743
1975
|
##
|
|
@@ -1755,7 +1987,6 @@ STANDARD_LOG_FORMAT_PARTS = [
|
|
|
1755
1987
|
|
|
1756
1988
|
|
|
1757
1989
|
class StandardLogFormatter(logging.Formatter):
|
|
1758
|
-
|
|
1759
1990
|
@staticmethod
|
|
1760
1991
|
def build_log_format(parts: ta.Iterable[ta.Tuple[str, str]]) -> str:
|
|
1761
1992
|
return ' '.join(v for k, v in parts)
|
|
@@ -1774,110 +2005,12 @@ class StandardLogFormatter(logging.Formatter):
|
|
|
1774
2005
|
##
|
|
1775
2006
|
|
|
1776
2007
|
|
|
1777
|
-
class
|
|
1778
|
-
def
|
|
1779
|
-
|
|
2008
|
+
class StandardConfiguredLogHandler(ProxyLogHandler):
|
|
2009
|
+
def __init_subclass__(cls, **kwargs):
|
|
2010
|
+
raise TypeError('This class serves only as a marker and should not be subclassed.')
|
|
1780
2011
|
|
|
1781
|
-
@property
|
|
1782
|
-
def underlying(self) -> logging.Filterer:
|
|
1783
|
-
return self._underlying
|
|
1784
2012
|
|
|
1785
|
-
|
|
1786
|
-
def filters(self):
|
|
1787
|
-
return self._underlying.filters
|
|
1788
|
-
|
|
1789
|
-
@filters.setter
|
|
1790
|
-
def filters(self, filters):
|
|
1791
|
-
self._underlying.filters = filters
|
|
1792
|
-
|
|
1793
|
-
def addFilter(self, filter): # noqa
|
|
1794
|
-
self._underlying.addFilter(filter)
|
|
1795
|
-
|
|
1796
|
-
def removeFilter(self, filter): # noqa
|
|
1797
|
-
self._underlying.removeFilter(filter)
|
|
1798
|
-
|
|
1799
|
-
def filter(self, record):
|
|
1800
|
-
return self._underlying.filter(record)
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
class ProxyLogHandler(ProxyLogFilterer, logging.Handler):
|
|
1804
|
-
def __init__(self, underlying: logging.Handler) -> None: # noqa
|
|
1805
|
-
ProxyLogFilterer.__init__(self, underlying)
|
|
1806
|
-
|
|
1807
|
-
_underlying: logging.Handler
|
|
1808
|
-
|
|
1809
|
-
@property
|
|
1810
|
-
def underlying(self) -> logging.Handler:
|
|
1811
|
-
return self._underlying
|
|
1812
|
-
|
|
1813
|
-
def get_name(self):
|
|
1814
|
-
return self._underlying.get_name()
|
|
1815
|
-
|
|
1816
|
-
def set_name(self, name):
|
|
1817
|
-
self._underlying.set_name(name)
|
|
1818
|
-
|
|
1819
|
-
@property
|
|
1820
|
-
def name(self):
|
|
1821
|
-
return self._underlying.name
|
|
1822
|
-
|
|
1823
|
-
@property
|
|
1824
|
-
def level(self):
|
|
1825
|
-
return self._underlying.level
|
|
1826
|
-
|
|
1827
|
-
@level.setter
|
|
1828
|
-
def level(self, level):
|
|
1829
|
-
self._underlying.level = level
|
|
1830
|
-
|
|
1831
|
-
@property
|
|
1832
|
-
def formatter(self):
|
|
1833
|
-
return self._underlying.formatter
|
|
1834
|
-
|
|
1835
|
-
@formatter.setter
|
|
1836
|
-
def formatter(self, formatter):
|
|
1837
|
-
self._underlying.formatter = formatter
|
|
1838
|
-
|
|
1839
|
-
def createLock(self):
|
|
1840
|
-
self._underlying.createLock()
|
|
1841
|
-
|
|
1842
|
-
def acquire(self):
|
|
1843
|
-
self._underlying.acquire()
|
|
1844
|
-
|
|
1845
|
-
def release(self):
|
|
1846
|
-
self._underlying.release()
|
|
1847
|
-
|
|
1848
|
-
def setLevel(self, level):
|
|
1849
|
-
self._underlying.setLevel(level)
|
|
1850
|
-
|
|
1851
|
-
def format(self, record):
|
|
1852
|
-
return self._underlying.format(record)
|
|
1853
|
-
|
|
1854
|
-
def emit(self, record):
|
|
1855
|
-
self._underlying.emit(record)
|
|
1856
|
-
|
|
1857
|
-
def handle(self, record):
|
|
1858
|
-
return self._underlying.handle(record)
|
|
1859
|
-
|
|
1860
|
-
def setFormatter(self, fmt):
|
|
1861
|
-
self._underlying.setFormatter(fmt)
|
|
1862
|
-
|
|
1863
|
-
def flush(self):
|
|
1864
|
-
self._underlying.flush()
|
|
1865
|
-
|
|
1866
|
-
def close(self):
|
|
1867
|
-
self._underlying.close()
|
|
1868
|
-
|
|
1869
|
-
def handleError(self, record):
|
|
1870
|
-
self._underlying.handleError(record)
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
##
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
class StandardLogHandler(ProxyLogHandler):
|
|
1877
|
-
pass
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
##
|
|
2013
|
+
##
|
|
1881
2014
|
|
|
1882
2015
|
|
|
1883
2016
|
@contextlib.contextmanager
|
|
@@ -1905,7 +2038,7 @@ def configure_standard_logging(
|
|
|
1905
2038
|
target: ta.Optional[logging.Logger] = None,
|
|
1906
2039
|
force: bool = False,
|
|
1907
2040
|
handler_factory: ta.Optional[ta.Callable[[], logging.Handler]] = None,
|
|
1908
|
-
) -> ta.Optional[
|
|
2041
|
+
) -> ta.Optional[StandardConfiguredLogHandler]:
|
|
1909
2042
|
with _locking_logging_module_lock():
|
|
1910
2043
|
if target is None:
|
|
1911
2044
|
target = logging.root
|
|
@@ -1913,7 +2046,7 @@ def configure_standard_logging(
|
|
|
1913
2046
|
#
|
|
1914
2047
|
|
|
1915
2048
|
if not force:
|
|
1916
|
-
if any(isinstance(h,
|
|
2049
|
+
if any(isinstance(h, StandardConfiguredLogHandler) for h in list(target.handlers)):
|
|
1917
2050
|
return None
|
|
1918
2051
|
|
|
1919
2052
|
#
|
|
@@ -1947,121 +2080,11 @@ def configure_standard_logging(
|
|
|
1947
2080
|
|
|
1948
2081
|
#
|
|
1949
2082
|
|
|
1950
|
-
return
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
########################################
|
|
1954
|
-
# ../../../omlish/lite/runtime.py
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
@cached_nullary
|
|
1958
|
-
def is_debugger_attached() -> bool:
|
|
1959
|
-
return any(frame[1].endswith('pydevd.py') for frame in inspect.stack())
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
REQUIRED_PYTHON_VERSION = (3, 8)
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
def check_runtime_version() -> None:
|
|
1966
|
-
if sys.version_info < REQUIRED_PYTHON_VERSION:
|
|
1967
|
-
raise OSError(f'Requires python {REQUIRED_PYTHON_VERSION}, got {sys.version_info} from {sys.executable}') # noqa
|
|
2083
|
+
return StandardConfiguredLogHandler(handler)
|
|
1968
2084
|
|
|
1969
2085
|
|
|
1970
2086
|
########################################
|
|
1971
|
-
#
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
# See https://peps.python.org/pep-3149/
|
|
1975
|
-
INTERP_OPT_GLYPHS_BY_ATTR: ta.Mapping[str, str] = collections.OrderedDict([
|
|
1976
|
-
('debug', 'd'),
|
|
1977
|
-
('threaded', 't'),
|
|
1978
|
-
])
|
|
1979
|
-
|
|
1980
|
-
INTERP_OPT_ATTRS_BY_GLYPH: ta.Mapping[str, str] = collections.OrderedDict(
|
|
1981
|
-
(g, a) for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items()
|
|
1982
|
-
)
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
@dc.dataclass(frozen=True)
|
|
1986
|
-
class InterpOpts:
|
|
1987
|
-
threaded: bool = False
|
|
1988
|
-
debug: bool = False
|
|
1989
|
-
|
|
1990
|
-
def __str__(self) -> str:
|
|
1991
|
-
return ''.join(g for a, g in INTERP_OPT_GLYPHS_BY_ATTR.items() if getattr(self, a))
|
|
1992
|
-
|
|
1993
|
-
@classmethod
|
|
1994
|
-
def parse(cls, s: str) -> 'InterpOpts':
|
|
1995
|
-
return cls(**{INTERP_OPT_ATTRS_BY_GLYPH[g]: True for g in s})
|
|
1996
|
-
|
|
1997
|
-
@classmethod
|
|
1998
|
-
def parse_suffix(cls, s: str) -> ta.Tuple[str, 'InterpOpts']:
|
|
1999
|
-
kw = {}
|
|
2000
|
-
while s and (a := INTERP_OPT_ATTRS_BY_GLYPH.get(s[-1])):
|
|
2001
|
-
s, kw[a] = s[:-1], True
|
|
2002
|
-
return s, cls(**kw)
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
@dc.dataclass(frozen=True)
|
|
2006
|
-
class InterpVersion:
|
|
2007
|
-
version: Version
|
|
2008
|
-
opts: InterpOpts
|
|
2009
|
-
|
|
2010
|
-
def __str__(self) -> str:
|
|
2011
|
-
return str(self.version) + str(self.opts)
|
|
2012
|
-
|
|
2013
|
-
@classmethod
|
|
2014
|
-
def parse(cls, s: str) -> 'InterpVersion':
|
|
2015
|
-
s, o = InterpOpts.parse_suffix(s)
|
|
2016
|
-
v = Version(s)
|
|
2017
|
-
return cls(
|
|
2018
|
-
version=v,
|
|
2019
|
-
opts=o,
|
|
2020
|
-
)
|
|
2021
|
-
|
|
2022
|
-
@classmethod
|
|
2023
|
-
def try_parse(cls, s: str) -> ta.Optional['InterpVersion']:
|
|
2024
|
-
try:
|
|
2025
|
-
return cls.parse(s)
|
|
2026
|
-
except (KeyError, InvalidVersion):
|
|
2027
|
-
return None
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
@dc.dataclass(frozen=True)
|
|
2031
|
-
class InterpSpecifier:
|
|
2032
|
-
specifier: Specifier
|
|
2033
|
-
opts: InterpOpts
|
|
2034
|
-
|
|
2035
|
-
def __str__(self) -> str:
|
|
2036
|
-
return str(self.specifier) + str(self.opts)
|
|
2037
|
-
|
|
2038
|
-
@classmethod
|
|
2039
|
-
def parse(cls, s: str) -> 'InterpSpecifier':
|
|
2040
|
-
s, o = InterpOpts.parse_suffix(s)
|
|
2041
|
-
if not any(s.startswith(o) for o in Specifier.OPERATORS):
|
|
2042
|
-
s = '~=' + s
|
|
2043
|
-
if s.count('.') < 2:
|
|
2044
|
-
s += '.0'
|
|
2045
|
-
return cls(
|
|
2046
|
-
specifier=Specifier(s),
|
|
2047
|
-
opts=o,
|
|
2048
|
-
)
|
|
2049
|
-
|
|
2050
|
-
def contains(self, iv: InterpVersion) -> bool:
|
|
2051
|
-
return self.specifier.contains(iv.version) and self.opts == iv.opts
|
|
2052
|
-
|
|
2053
|
-
def __contains__(self, iv: InterpVersion) -> bool:
|
|
2054
|
-
return self.contains(iv)
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
@dc.dataclass(frozen=True)
|
|
2058
|
-
class Interp:
|
|
2059
|
-
exe: str
|
|
2060
|
-
version: InterpVersion
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
########################################
|
|
2064
|
-
# ../../../omlish/lite/subprocesses.py
|
|
2087
|
+
# ../../../omlish/subprocesses.py
|
|
2065
2088
|
|
|
2066
2089
|
|
|
2067
2090
|
##
|
|
@@ -2112,8 +2135,8 @@ def subprocess_close(
|
|
|
2112
2135
|
##
|
|
2113
2136
|
|
|
2114
2137
|
|
|
2115
|
-
class
|
|
2116
|
-
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] =
|
|
2138
|
+
class BaseSubprocesses(abc.ABC): # noqa
|
|
2139
|
+
DEFAULT_LOGGER: ta.ClassVar[ta.Optional[logging.Logger]] = None
|
|
2117
2140
|
|
|
2118
2141
|
def __init__(
|
|
2119
2142
|
self,
|
|
@@ -2126,6 +2149,9 @@ class AbstractSubprocesses(abc.ABC): # noqa
|
|
|
2126
2149
|
self._log = log if log is not None else self.DEFAULT_LOGGER
|
|
2127
2150
|
self._try_exceptions = try_exceptions if try_exceptions is not None else self.DEFAULT_TRY_EXCEPTIONS
|
|
2128
2151
|
|
|
2152
|
+
def set_logger(self, log: ta.Optional[logging.Logger]) -> None:
|
|
2153
|
+
self._log = log
|
|
2154
|
+
|
|
2129
2155
|
#
|
|
2130
2156
|
|
|
2131
2157
|
def prepare_args(
|
|
@@ -2237,23 +2263,25 @@ class AbstractSubprocesses(abc.ABC): # noqa
|
|
|
2237
2263
|
##
|
|
2238
2264
|
|
|
2239
2265
|
|
|
2240
|
-
class
|
|
2266
|
+
class AbstractSubprocesses(BaseSubprocesses, abc.ABC):
|
|
2267
|
+
@abc.abstractmethod
|
|
2241
2268
|
def check_call(
|
|
2242
2269
|
self,
|
|
2243
2270
|
*cmd: str,
|
|
2244
2271
|
stdout: ta.Any = sys.stderr,
|
|
2245
2272
|
**kwargs: ta.Any,
|
|
2246
2273
|
) -> None:
|
|
2247
|
-
|
|
2248
|
-
subprocess.check_call(cmd, **kwargs)
|
|
2274
|
+
raise NotImplementedError
|
|
2249
2275
|
|
|
2276
|
+
@abc.abstractmethod
|
|
2250
2277
|
def check_output(
|
|
2251
2278
|
self,
|
|
2252
2279
|
*cmd: str,
|
|
2253
2280
|
**kwargs: ta.Any,
|
|
2254
2281
|
) -> bytes:
|
|
2255
|
-
|
|
2256
|
-
|
|
2282
|
+
raise NotImplementedError
|
|
2283
|
+
|
|
2284
|
+
#
|
|
2257
2285
|
|
|
2258
2286
|
def check_output_str(
|
|
2259
2287
|
self,
|
|
@@ -2295,11 +2323,96 @@ class Subprocesses(AbstractSubprocesses):
|
|
|
2295
2323
|
return ret.decode().strip()
|
|
2296
2324
|
|
|
2297
2325
|
|
|
2326
|
+
##
|
|
2327
|
+
|
|
2328
|
+
|
|
2329
|
+
class Subprocesses(AbstractSubprocesses):
|
|
2330
|
+
def check_call(
|
|
2331
|
+
self,
|
|
2332
|
+
*cmd: str,
|
|
2333
|
+
stdout: ta.Any = sys.stderr,
|
|
2334
|
+
**kwargs: ta.Any,
|
|
2335
|
+
) -> None:
|
|
2336
|
+
with self.prepare_and_wrap(*cmd, stdout=stdout, **kwargs) as (cmd, kwargs): # noqa
|
|
2337
|
+
subprocess.check_call(cmd, **kwargs)
|
|
2338
|
+
|
|
2339
|
+
def check_output(
|
|
2340
|
+
self,
|
|
2341
|
+
*cmd: str,
|
|
2342
|
+
**kwargs: ta.Any,
|
|
2343
|
+
) -> bytes:
|
|
2344
|
+
with self.prepare_and_wrap(*cmd, **kwargs) as (cmd, kwargs): # noqa
|
|
2345
|
+
return subprocess.check_output(cmd, **kwargs)
|
|
2346
|
+
|
|
2347
|
+
|
|
2298
2348
|
subprocesses = Subprocesses()
|
|
2299
2349
|
|
|
2300
2350
|
|
|
2351
|
+
##
|
|
2352
|
+
|
|
2353
|
+
|
|
2354
|
+
class AbstractAsyncSubprocesses(BaseSubprocesses):
|
|
2355
|
+
@abc.abstractmethod
|
|
2356
|
+
async def check_call(
|
|
2357
|
+
self,
|
|
2358
|
+
*cmd: str,
|
|
2359
|
+
stdout: ta.Any = sys.stderr,
|
|
2360
|
+
**kwargs: ta.Any,
|
|
2361
|
+
) -> None:
|
|
2362
|
+
raise NotImplementedError
|
|
2363
|
+
|
|
2364
|
+
@abc.abstractmethod
|
|
2365
|
+
async def check_output(
|
|
2366
|
+
self,
|
|
2367
|
+
*cmd: str,
|
|
2368
|
+
**kwargs: ta.Any,
|
|
2369
|
+
) -> bytes:
|
|
2370
|
+
raise NotImplementedError
|
|
2371
|
+
|
|
2372
|
+
#
|
|
2373
|
+
|
|
2374
|
+
async def check_output_str(
|
|
2375
|
+
self,
|
|
2376
|
+
*cmd: str,
|
|
2377
|
+
**kwargs: ta.Any,
|
|
2378
|
+
) -> str:
|
|
2379
|
+
return (await self.check_output(*cmd, **kwargs)).decode().strip()
|
|
2380
|
+
|
|
2381
|
+
#
|
|
2382
|
+
|
|
2383
|
+
async def try_call(
|
|
2384
|
+
self,
|
|
2385
|
+
*cmd: str,
|
|
2386
|
+
**kwargs: ta.Any,
|
|
2387
|
+
) -> bool:
|
|
2388
|
+
if isinstance(await self.async_try_fn(self.check_call, *cmd, **kwargs), Exception):
|
|
2389
|
+
return False
|
|
2390
|
+
else:
|
|
2391
|
+
return True
|
|
2392
|
+
|
|
2393
|
+
async def try_output(
|
|
2394
|
+
self,
|
|
2395
|
+
*cmd: str,
|
|
2396
|
+
**kwargs: ta.Any,
|
|
2397
|
+
) -> ta.Optional[bytes]:
|
|
2398
|
+
if isinstance(ret := await self.async_try_fn(self.check_output, *cmd, **kwargs), Exception):
|
|
2399
|
+
return None
|
|
2400
|
+
else:
|
|
2401
|
+
return ret
|
|
2402
|
+
|
|
2403
|
+
async def try_output_str(
|
|
2404
|
+
self,
|
|
2405
|
+
*cmd: str,
|
|
2406
|
+
**kwargs: ta.Any,
|
|
2407
|
+
) -> ta.Optional[str]:
|
|
2408
|
+
if (ret := await self.try_output(*cmd, **kwargs)) is None:
|
|
2409
|
+
return None
|
|
2410
|
+
else:
|
|
2411
|
+
return ret.decode().strip()
|
|
2412
|
+
|
|
2413
|
+
|
|
2301
2414
|
########################################
|
|
2302
|
-
# ../../../omlish/
|
|
2415
|
+
# ../../../omlish/asyncs/asyncio/subprocesses.py
|
|
2303
2416
|
|
|
2304
2417
|
|
|
2305
2418
|
##
|
|
@@ -2310,6 +2423,8 @@ class AsyncioProcessCommunicator:
|
|
|
2310
2423
|
self,
|
|
2311
2424
|
proc: asyncio.subprocess.Process,
|
|
2312
2425
|
loop: ta.Optional[ta.Any] = None,
|
|
2426
|
+
*,
|
|
2427
|
+
log: ta.Optional[logging.Logger] = None,
|
|
2313
2428
|
) -> None:
|
|
2314
2429
|
super().__init__()
|
|
2315
2430
|
|
|
@@ -2318,6 +2433,7 @@ class AsyncioProcessCommunicator:
|
|
|
2318
2433
|
|
|
2319
2434
|
self._proc = proc
|
|
2320
2435
|
self._loop = loop
|
|
2436
|
+
self._log = log
|
|
2321
2437
|
|
|
2322
2438
|
self._transport: asyncio.base_subprocess.BaseSubprocessTransport = check.isinstance(
|
|
2323
2439
|
proc._transport, # type: ignore # noqa
|
|
@@ -2333,19 +2449,19 @@ class AsyncioProcessCommunicator:
|
|
|
2333
2449
|
try:
|
|
2334
2450
|
if input is not None:
|
|
2335
2451
|
stdin.write(input)
|
|
2336
|
-
if self._debug:
|
|
2337
|
-
|
|
2452
|
+
if self._debug and self._log is not None:
|
|
2453
|
+
self._log.debug('%r communicate: feed stdin (%s bytes)', self, len(input))
|
|
2338
2454
|
|
|
2339
2455
|
await stdin.drain()
|
|
2340
2456
|
|
|
2341
2457
|
except (BrokenPipeError, ConnectionResetError) as exc:
|
|
2342
2458
|
# communicate() ignores BrokenPipeError and ConnectionResetError. write() and drain() can raise these
|
|
2343
2459
|
# exceptions.
|
|
2344
|
-
if self._debug:
|
|
2345
|
-
|
|
2460
|
+
if self._debug and self._log is not None:
|
|
2461
|
+
self._log.debug('%r communicate: stdin got %r', self, exc)
|
|
2346
2462
|
|
|
2347
|
-
if self._debug:
|
|
2348
|
-
|
|
2463
|
+
if self._debug and self._log is not None:
|
|
2464
|
+
self._log.debug('%r communicate: close stdin', self)
|
|
2349
2465
|
|
|
2350
2466
|
stdin.close()
|
|
2351
2467
|
|
|
@@ -2361,15 +2477,15 @@ class AsyncioProcessCommunicator:
|
|
|
2361
2477
|
check.equal(fd, 1)
|
|
2362
2478
|
stream = check.not_none(self._proc.stdout)
|
|
2363
2479
|
|
|
2364
|
-
if self._debug:
|
|
2480
|
+
if self._debug and self._log is not None:
|
|
2365
2481
|
name = 'stdout' if fd == 1 else 'stderr'
|
|
2366
|
-
|
|
2482
|
+
self._log.debug('%r communicate: read %s', self, name)
|
|
2367
2483
|
|
|
2368
2484
|
output = await stream.read()
|
|
2369
2485
|
|
|
2370
|
-
if self._debug:
|
|
2486
|
+
if self._debug and self._log is not None:
|
|
2371
2487
|
name = 'stdout' if fd == 1 else 'stderr'
|
|
2372
|
-
|
|
2488
|
+
self._log.debug('%r communicate: close %s', self, name)
|
|
2373
2489
|
|
|
2374
2490
|
transport.close()
|
|
2375
2491
|
|
|
@@ -2418,7 +2534,7 @@ class AsyncioProcessCommunicator:
|
|
|
2418
2534
|
##
|
|
2419
2535
|
|
|
2420
2536
|
|
|
2421
|
-
class AsyncioSubprocesses(
|
|
2537
|
+
class AsyncioSubprocesses(AbstractAsyncSubprocesses):
|
|
2422
2538
|
async def communicate(
|
|
2423
2539
|
self,
|
|
2424
2540
|
proc: asyncio.subprocess.Process,
|
|
@@ -2515,45 +2631,6 @@ class AsyncioSubprocesses(AbstractSubprocesses):
|
|
|
2515
2631
|
with self.prepare_and_wrap(*cmd, stdout=subprocess.PIPE, check=True, **kwargs) as (cmd, kwargs): # noqa
|
|
2516
2632
|
return check.not_none((await self.run(*cmd, **kwargs)).stdout)
|
|
2517
2633
|
|
|
2518
|
-
async def check_output_str(
|
|
2519
|
-
self,
|
|
2520
|
-
*cmd: str,
|
|
2521
|
-
**kwargs: ta.Any,
|
|
2522
|
-
) -> str:
|
|
2523
|
-
return (await self.check_output(*cmd, **kwargs)).decode().strip()
|
|
2524
|
-
|
|
2525
|
-
#
|
|
2526
|
-
|
|
2527
|
-
async def try_call(
|
|
2528
|
-
self,
|
|
2529
|
-
*cmd: str,
|
|
2530
|
-
**kwargs: ta.Any,
|
|
2531
|
-
) -> bool:
|
|
2532
|
-
if isinstance(await self.async_try_fn(self.check_call, *cmd, **kwargs), Exception):
|
|
2533
|
-
return False
|
|
2534
|
-
else:
|
|
2535
|
-
return True
|
|
2536
|
-
|
|
2537
|
-
async def try_output(
|
|
2538
|
-
self,
|
|
2539
|
-
*cmd: str,
|
|
2540
|
-
**kwargs: ta.Any,
|
|
2541
|
-
) -> ta.Optional[bytes]:
|
|
2542
|
-
if isinstance(ret := await self.async_try_fn(self.check_output, *cmd, **kwargs), Exception):
|
|
2543
|
-
return None
|
|
2544
|
-
else:
|
|
2545
|
-
return ret
|
|
2546
|
-
|
|
2547
|
-
async def try_output_str(
|
|
2548
|
-
self,
|
|
2549
|
-
*cmd: str,
|
|
2550
|
-
**kwargs: ta.Any,
|
|
2551
|
-
) -> ta.Optional[str]:
|
|
2552
|
-
if (ret := await self.try_output(*cmd, **kwargs)) is None:
|
|
2553
|
-
return None
|
|
2554
|
-
else:
|
|
2555
|
-
return ret.decode().strip()
|
|
2556
|
-
|
|
2557
2634
|
|
|
2558
2635
|
asyncio_subprocesses = AsyncioSubprocesses()
|
|
2559
2636
|
|
|
@@ -3411,7 +3488,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
3411
3488
|
|
|
3412
3489
|
|
|
3413
3490
|
async def _async_main(argv: ta.Optional[ta.Sequence[str]] = None) -> None:
|
|
3414
|
-
|
|
3491
|
+
check_lite_runtime_version()
|
|
3415
3492
|
configure_standard_logging()
|
|
3416
3493
|
|
|
3417
3494
|
parser = _build_parser()
|