ominfra 0.0.0.dev133__tar.gz → 0.0.0.dev134__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. {ominfra-0.0.0.dev133/ominfra.egg-info → ominfra-0.0.0.dev134}/PKG-INFO +3 -3
  2. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/pyremote.py +44 -12
  3. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134/ominfra.egg-info}/PKG-INFO +3 -3
  4. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra.egg-info/requires.txt +2 -2
  5. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/pyproject.toml +3 -3
  6. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/LICENSE +0 -0
  7. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/MANIFEST.in +0 -0
  8. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/README.rst +0 -0
  9. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/.manifests.json +0 -0
  10. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/__about__.py +0 -0
  11. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/__init__.py +0 -0
  12. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/__init__.py +0 -0
  13. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/__init__.py +0 -0
  14. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/__main__.py +0 -0
  15. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/auth.py +0 -0
  16. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/cli.py +0 -0
  17. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/dataclasses.py +0 -0
  18. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/journald2aws/__init__.py +0 -0
  19. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/journald2aws/__main__.py +0 -0
  20. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/journald2aws/cursor.py +0 -0
  21. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/journald2aws/driver.py +0 -0
  22. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/journald2aws/main.py +0 -0
  23. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/journald2aws/poster.py +0 -0
  24. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/logs.py +0 -0
  25. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/aws/metadata.py +0 -0
  26. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/gcp/__init__.py +0 -0
  27. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/clouds/gcp/auth.py +0 -0
  28. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/cmds.py +0 -0
  29. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/configs.py +0 -0
  30. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/journald/__init__.py +0 -0
  31. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/journald/fields.py +0 -0
  32. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/journald/genmessages.py +0 -0
  33. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/journald/messages.py +0 -0
  34. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/journald/tailer.py +0 -0
  35. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/__init__.py +0 -0
  36. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/__init__.py +0 -0
  37. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/_executor.py +0 -0
  38. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/configs.py +0 -0
  39. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/__init__.py +0 -0
  40. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/base.py +0 -0
  41. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/concerns/__init__.py +0 -0
  42. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/concerns/dirs.py +0 -0
  43. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/concerns/nginx.py +0 -0
  44. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/concerns/repo.py +0 -0
  45. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/concerns/supervisor.py +0 -0
  46. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/concerns/systemd.py +0 -0
  47. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/concerns/user.py +0 -0
  48. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/concerns/venv.py +0 -0
  49. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/executor/main.py +0 -0
  50. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/__init__.py +0 -0
  51. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/_main.py +0 -0
  52. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/base.py +0 -0
  53. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/configs.py +0 -0
  54. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/deploy.py +0 -0
  55. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/main.py +0 -0
  56. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/nginx.py +0 -0
  57. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/repo.py +0 -0
  58. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/runtime.py +0 -0
  59. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/site.py +0 -0
  60. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/supervisor.py +0 -0
  61. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/poly/venv.py +0 -0
  62. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/deploy/remote.py +0 -0
  63. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/manage/manage.py +0 -0
  64. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/scripts/__init__.py +0 -0
  65. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/scripts/journald2aws.py +0 -0
  66. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/scripts/supervisor.py +0 -0
  67. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/ssh.py +0 -0
  68. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/LICENSE.txt +0 -0
  69. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/__init__.py +0 -0
  70. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/__main__.py +0 -0
  71. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/configs.py +0 -0
  72. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/dispatchers.py +0 -0
  73. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/dispatchersimpl.py +0 -0
  74. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/events.py +0 -0
  75. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/exceptions.py +0 -0
  76. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/groups.py +0 -0
  77. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/groupsimpl.py +0 -0
  78. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/http.py +0 -0
  79. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/inject.py +0 -0
  80. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/io.py +0 -0
  81. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/main.py +0 -0
  82. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/pipes.py +0 -0
  83. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/privileges.py +0 -0
  84. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/process.py +0 -0
  85. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/processimpl.py +0 -0
  86. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/setup.py +0 -0
  87. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/setupimpl.py +0 -0
  88. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/signals.py +0 -0
  89. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/spawning.py +0 -0
  90. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/spawningimpl.py +0 -0
  91. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/states.py +0 -0
  92. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/supervisor.py +0 -0
  93. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/types.py +0 -0
  94. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/__init__.py +0 -0
  95. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/collections.py +0 -0
  96. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/diag.py +0 -0
  97. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/fds.py +0 -0
  98. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/fs.py +0 -0
  99. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/os.py +0 -0
  100. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/ostypes.py +0 -0
  101. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/signals.py +0 -0
  102. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/strings.py +0 -0
  103. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/supervisor/utils/users.py +0 -0
  104. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/tailscale/__init__.py +0 -0
  105. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/tailscale/api.py +0 -0
  106. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/tailscale/cli.py +0 -0
  107. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/threadworkers.py +0 -0
  108. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/tools/__init__.py +0 -0
  109. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra/tools/listresources.py +0 -0
  110. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra.egg-info/SOURCES.txt +0 -0
  111. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra.egg-info/dependency_links.txt +0 -0
  112. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra.egg-info/entry_points.txt +0 -0
  113. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/ominfra.egg-info/top_level.txt +0 -0
  114. {ominfra-0.0.0.dev133 → ominfra-0.0.0.dev134}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev133
3
+ Version: 0.0.0.dev134
4
4
  Summary: ominfra
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,8 +12,8 @@ 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: omdev==0.0.0.dev133
16
- Requires-Dist: omlish==0.0.0.dev133
15
+ Requires-Dist: omdev==0.0.0.dev134
16
+ Requires-Dist: omlish==0.0.0.dev134
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko~=3.5; extra == "all"
19
19
  Requires-Dist: asyncssh~=2.18; extra == "all"
@@ -17,9 +17,6 @@ import textwrap
17
17
  import typing as ta
18
18
  import zlib
19
19
 
20
- from omlish.lite.check import check_isinstance
21
- from omlish.lite.check import check_none
22
-
23
20
 
24
21
  ##
25
22
 
@@ -32,8 +29,8 @@ _PYREMOTE_BOOTSTRAP_ARGV0_VAR = '_OPYR_ARGV0'
32
29
 
33
30
  _PYREMOTE_BOOTSTRAP_ACK0 = b'OPYR000\n'
34
31
  _PYREMOTE_BOOTSTRAP_ACK1 = b'OPYR001\n'
35
- _PYREMOTE_BOOTSTRAP_ACK2 = b'OPYR001\n'
36
- _PYREMOTE_BOOTSTRAP_ACK3 = b'OPYR001\n'
32
+ _PYREMOTE_BOOTSTRAP_ACK2 = b'OPYR002\n'
33
+ _PYREMOTE_BOOTSTRAP_ACK3 = b'OPYR003\n'
37
34
 
38
35
  _PYREMOTE_BOOTSTRAP_PROC_TITLE_FMT = '(pyremote:%s)'
39
36
 
@@ -256,6 +253,8 @@ class PyremoteBootstrapDriver:
256
253
  self._main_src = main_src
257
254
  self._main_z = zlib.compress(main_src.encode('utf-8'))
258
255
 
256
+ #
257
+
259
258
  @dc.dataclass(frozen=True)
260
259
  class Read:
261
260
  sz: int
@@ -272,7 +271,7 @@ class PyremoteBootstrapDriver:
272
271
  pid: int
273
272
  env_info: PyremoteEnvInfo
274
273
 
275
- def __call__(self) -> ta.Generator[ta.Union[Read, Write], ta.Optional[bytes], Result]:
274
+ def gen(self) -> ta.Generator[ta.Union[Read, Write], ta.Optional[bytes], Result]:
276
275
  # Read first ack
277
276
  yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK0)
278
277
 
@@ -281,8 +280,8 @@ class PyremoteBootstrapDriver:
281
280
  pid = struct.unpack('<Q', d)[0]
282
281
 
283
282
  # Write main src
284
- check_none((yield self.Write(struct.pack('<I', len(self._main_z)))))
285
- check_none((yield self.Write(self._main_z)))
283
+ yield from self._write(struct.pack('<I', len(self._main_z)))
284
+ yield from self._write(self._main_z)
286
285
 
287
286
  # Read second and third ack
288
287
  yield from self._expect(_PYREMOTE_BOOTSTRAP_ACK1)
@@ -305,7 +304,9 @@ class PyremoteBootstrapDriver:
305
304
  )
306
305
 
307
306
  def _read(self, sz: int) -> ta.Generator[Read, bytes, bytes]:
308
- d = check_isinstance((yield self.Read(sz)), bytes)
307
+ d = yield self.Read(sz)
308
+ if not isinstance(d, bytes):
309
+ raise self.ProtocolError(f'Expected bytes after read, got {d!r}')
309
310
  if len(d) != sz:
310
311
  raise self.ProtocolError(f'Read {len(d)} bytes, expected {sz}')
311
312
  return d
@@ -315,17 +316,47 @@ class PyremoteBootstrapDriver:
315
316
  if d != e:
316
317
  raise self.ProtocolError(f'Read {d!r}, expected {e!r}')
317
318
 
319
+ def _write(self, d: bytes) -> ta.Generator[Write, ta.Optional[bytes], None]:
320
+ i = yield self.Write(d)
321
+ if i is not None:
322
+ raise self.ProtocolError('Unexpected input after write')
323
+
324
+ #
325
+
326
+ def run(self, stdin: ta.IO, stdout: ta.IO) -> Result:
327
+ gen = self.gen()
328
+
329
+ gi: bytes | None = None
330
+ while True:
331
+ try:
332
+ if gi is not None:
333
+ go = gen.send(gi)
334
+ else:
335
+ go = next(gen)
336
+ except StopIteration as e:
337
+ return e.value
338
+
339
+ if isinstance(go, self.Read):
340
+ gi = stdout.read(go.sz)
341
+ elif isinstance(go, self.Write):
342
+ gi = None
343
+ stdin.write(go.d)
344
+ stdin.flush()
345
+ else:
346
+ raise TypeError(go)
347
+
318
348
 
319
349
  ##
320
350
 
321
351
 
322
352
  @dc.dataclass(frozen=True)
323
- class PyremoteBootstrapPayloadRuntime:
353
+ class PyremotePayloadRuntime:
324
354
  input: ta.BinaryIO
325
355
  main_src: str
356
+ env_info: PyremoteEnvInfo
326
357
 
327
358
 
328
- def pyremote_bootstrap_finalize() -> PyremoteBootstrapPayloadRuntime:
359
+ def pyremote_bootstrap_finalize() -> PyremotePayloadRuntime:
329
360
  # Restore original argv0
330
361
  sys.executable = os.environ.pop(_PYREMOTE_BOOTSTRAP_ARGV0_VAR)
331
362
 
@@ -351,7 +382,8 @@ def pyremote_bootstrap_finalize() -> PyremoteBootstrapPayloadRuntime:
351
382
  os.write(1, _PYREMOTE_BOOTSTRAP_ACK3)
352
383
 
353
384
  # Return
354
- return PyremoteBootstrapPayloadRuntime(
385
+ return PyremotePayloadRuntime(
355
386
  input=os.fdopen(_PYREMOTE_BOOTSTRAP_COMM_FD, 'rb', 0),
356
387
  main_src=main_src,
388
+ env_info=env_info,
357
389
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: ominfra
3
- Version: 0.0.0.dev133
3
+ Version: 0.0.0.dev134
4
4
  Summary: ominfra
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -12,8 +12,8 @@ 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: omdev==0.0.0.dev133
16
- Requires-Dist: omlish==0.0.0.dev133
15
+ Requires-Dist: omdev==0.0.0.dev134
16
+ Requires-Dist: omlish==0.0.0.dev134
17
17
  Provides-Extra: all
18
18
  Requires-Dist: paramiko~=3.5; extra == "all"
19
19
  Requires-Dist: asyncssh~=2.18; extra == "all"
@@ -1,5 +1,5 @@
1
- omdev==0.0.0.dev133
2
- omlish==0.0.0.dev133
1
+ omdev==0.0.0.dev134
2
+ omlish==0.0.0.dev134
3
3
 
4
4
  [all]
5
5
  paramiko~=3.5
@@ -12,7 +12,7 @@ authors = [
12
12
  urls = {source = 'https://github.com/wrmsr/omlish'}
13
13
  license = {text = 'BSD-3-Clause'}
14
14
  requires-python = '>=3.12'
15
- version = '0.0.0.dev133'
15
+ version = '0.0.0.dev134'
16
16
  classifiers = [
17
17
  'License :: OSI Approved :: BSD License',
18
18
  'Development Status :: 2 - Pre-Alpha',
@@ -22,8 +22,8 @@ classifiers = [
22
22
  ]
23
23
  description = 'ominfra'
24
24
  dependencies = [
25
- 'omdev == 0.0.0.dev133',
26
- 'omlish == 0.0.0.dev133',
25
+ 'omdev == 0.0.0.dev134',
26
+ 'omlish == 0.0.0.dev134',
27
27
  ]
28
28
 
29
29
  [project.optional-dependencies]
File without changes
File without changes