corio 2.2.1a0__tar.gz → 2.2.2__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.
- {corio-2.2.1a0 → corio-2.2.2}/PKG-INFO +7 -1
- {corio-2.2.1a0 → corio-2.2.2}/corio/entrypoint.py +2 -2
- {corio-2.2.1a0 → corio-2.2.2}/corio/infra/incrementor_pyproject.py +112 -35
- {corio-2.2.1a0 → corio-2.2.2}/corio/infra/releaser.py +175 -1
- {corio-2.2.1a0 → corio-2.2.2}/corio/infra/stack.py +4 -4
- {corio-2.2.1a0 → corio-2.2.2}/corio/logs.py +10 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/path/path.py +10 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/pyproject.package.toml +10 -9
- corio-2.2.2/corio/tests/test_caching.py +39 -0
- corio-2.2.2/corio/tests/test_datatype.py +24 -0
- corio-2.2.2/corio/tests/test_encrypt.py +43 -0
- corio-2.2.2/corio/tests/test_infra.py +163 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/tests/test_path.py +13 -8
- {corio-2.2.1a0 → corio-2.2.2}/corio.egg-info/PKG-INFO +7 -1
- {corio-2.2.1a0 → corio-2.2.2}/corio.egg-info/SOURCES.txt +6 -3
- {corio-2.2.1a0 → corio-2.2.2}/corio.egg-info/requires.txt +6 -0
- {corio-2.2.1a0 → corio-2.2.2}/pyproject.toml +10 -9
- corio-2.2.1a0/corio/tests/test_datatype.py +0 -33
- {corio-2.2.1a0 → corio-2.2.2}/LICENSE +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/README.md +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/ai/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/ai/agentic.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/ai/infer.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/aio.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/api.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/augmentation.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/av.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/caching.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/constants.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/context.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/dataclass.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/datatype.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/db/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/db/document.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/debug.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/dm.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/dns/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/dns/client.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/dns/dm.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/dns/proxy.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/dns/server.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/docker/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/dt.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/encrypt.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/env.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/function.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/google_api.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/ha/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/ha/constants.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/ha/core.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/ha/supervisor.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/ha/utils.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/hash.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/hfh.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/hook.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/https.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/infra/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/infra/api.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/infra/project.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/infra/repository.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/inherit.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/inspection.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/interface/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/interface/context.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/interface/controls.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/interface/interface.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/iterator.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/jsn.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/json_fix.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/markup.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/merging.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/metric.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/mqtt.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/name.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/net.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/netrc.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/openai.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/parallel.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/path/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/path/app.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/path/type.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/paths.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/patterns.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/pdf.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/plat.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/process.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/profiling.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/rand.py +0 -0
- /corio-2.2.1a0/corio/secrets.py → /corio-2.2.2/corio/sec.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/semantic.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/sets.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/setup/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/spaces.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/strings.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/tabular.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/tests/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/tests/conftest.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/tests/helpers.py +0 -0
- /corio-2.2.1a0/corio/tests/test_environment.py → /corio-2.2.2/corio/tests/test_env.py +0 -0
- /corio-2.2.1a0/corio/tests/test_json.py → /corio-2.2.2/corio/tests/test_jsn.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/tests/test_yaml.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/tokenization.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/toml.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/tools.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/unicode.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/version/__init__.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/version/version.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/webhook.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/yml.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio/youtube.py +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio.egg-info/dependency_links.txt +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio.egg-info/entry_points.txt +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/corio.egg-info/top_level.txt +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/add-service +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/add-user-path +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/add-ve-shell +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/apt-essentials +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/apt-headless +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/auth-token +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/compose-update +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/compress-dir +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/cru +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/docker-build-bases +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/docker-build-bases-dev +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/docker-install-deps +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/docker-install-prod +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/docker-prune +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/docker-sandbox +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/docker-sandbox-init +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/docs-deploy +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/download +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/encrypt-secrets +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/fmtr-test-script +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/git-clone +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/ha-addon-launch +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/infra +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/infra-sync +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/install-browser +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/install-docker +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/install-ts +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/install-ys +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/mirror-dir +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/opt-dev-init +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/parse-args +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/pypi-check +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/pypi-reserve +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/run-script +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/set-password +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/set-secure-path +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/set-user-sudo +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/snips-install +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/ssh-auth +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/ssh-serve +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/tasmota-config +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/tasmota-flash +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/tasmota-terminal +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/vlc-tn +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/scripts/vm-launch +0 -0
- {corio-2.2.1a0 → corio-2.2.2}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: corio
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Collection of high-level tools to simplify everyday development tasks, with a focus on AI/ML
|
|
5
5
|
Author-email: Frontmatter AI <innovative.fowler@mask.pro.fmtr.dev>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -39,7 +39,10 @@ Requires-Dist: logfire[fastapi]; extra == "dev"
|
|
|
39
39
|
Requires-Dist: tomlkit; extra == "dev"
|
|
40
40
|
Requires-Dist: pyrage; extra == "dev"
|
|
41
41
|
Requires-Dist: dotenv; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest; extra == "dev"
|
|
43
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
42
44
|
Provides-Extra: test
|
|
45
|
+
Requires-Dist: pytest; extra == "test"
|
|
43
46
|
Requires-Dist: pytest-cov; extra == "test"
|
|
44
47
|
Provides-Extra: yaml
|
|
45
48
|
Requires-Dist: yamlscript; extra == "yaml"
|
|
@@ -255,6 +258,8 @@ Requires-Dist: logfire[fastapi]; extra == "infra"
|
|
|
255
258
|
Requires-Dist: tomlkit; extra == "infra"
|
|
256
259
|
Requires-Dist: pyrage; extra == "infra"
|
|
257
260
|
Requires-Dist: dotenv; extra == "infra"
|
|
261
|
+
Requires-Dist: pytest; extra == "infra"
|
|
262
|
+
Requires-Dist: pytest-cov; extra == "infra"
|
|
258
263
|
Provides-Extra: vcs
|
|
259
264
|
Requires-Dist: pygit2; extra == "vcs"
|
|
260
265
|
Provides-Extra: tasmota
|
|
@@ -313,6 +318,7 @@ Requires-Dist: logfire[fastapi]; extra == "all"
|
|
|
313
318
|
Requires-Dist: tomlkit; extra == "all"
|
|
314
319
|
Requires-Dist: pyrage; extra == "all"
|
|
315
320
|
Requires-Dist: dotenv; extra == "all"
|
|
321
|
+
Requires-Dist: pytest; extra == "all"
|
|
316
322
|
Requires-Dist: pytest-cov; extra == "all"
|
|
317
323
|
Requires-Dist: dask[bag]; extra == "all"
|
|
318
324
|
Requires-Dist: distributed; extra == "all"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from pydantic_settings import CliSubCommand
|
|
2
2
|
|
|
3
3
|
from corio import dm
|
|
4
|
-
from corio import
|
|
4
|
+
from corio import sec
|
|
5
5
|
from corio import sets
|
|
6
6
|
|
|
7
7
|
|
|
@@ -78,7 +78,7 @@ class RemoteDebugTest(dm.Base):
|
|
|
78
78
|
|
|
79
79
|
|
|
80
80
|
class Cli(sets.Base, cli_parse_args=True):
|
|
81
|
-
secrets: CliSubCommand[
|
|
81
|
+
secrets: CliSubCommand[sec.Cli]
|
|
82
82
|
docs: CliSubCommand[Docs]
|
|
83
83
|
pyproject: CliSubCommand[Pyproject]
|
|
84
84
|
ep_test: CliSubCommand[EpTest]
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
from copy import deepcopy
|
|
2
2
|
from functools import cached_property
|
|
3
3
|
from itertools import chain
|
|
4
|
+
from packaging.requirements import Requirement, InvalidRequirement
|
|
5
|
+
from packaging.utils import canonicalize_name
|
|
4
6
|
|
|
5
7
|
from corio.constants import Constants
|
|
6
8
|
from corio.infra.releaser import Incrementor
|
|
7
9
|
from corio.iterator import dedupe
|
|
8
10
|
from corio.logs import logger
|
|
9
|
-
from corio.path import Path
|
|
11
|
+
from corio.path import Path, PackagePaths
|
|
12
|
+
from corio.path.path import Metadata
|
|
10
13
|
from corio.toml import ensure_table
|
|
11
14
|
|
|
12
15
|
|
|
@@ -25,6 +28,86 @@ class IncrementorPyproject(Incrementor):
|
|
|
25
28
|
def name_command(self) -> str:
|
|
26
29
|
return self.paths.name_ns.replace(".", self.ENTRYPOINT_COMMAND_SEP)
|
|
27
30
|
|
|
31
|
+
@cached_property
|
|
32
|
+
def editables(self) -> dict[str, Metadata]:
|
|
33
|
+
data = self.path.read_toml()
|
|
34
|
+
sources = data.get("tool", {}).get("uv", {}).get("sources", {})
|
|
35
|
+
|
|
36
|
+
editables = {}
|
|
37
|
+
for key, source in sources.items():
|
|
38
|
+
if not isinstance(source, dict):
|
|
39
|
+
continue
|
|
40
|
+
if not source.get("editable"):
|
|
41
|
+
continue
|
|
42
|
+
|
|
43
|
+
source_path = source.get("path")
|
|
44
|
+
if not source_path:
|
|
45
|
+
logger.warning(f'Editable source "{key}" is missing "path". Skipping.')
|
|
46
|
+
continue
|
|
47
|
+
path_repo = (self.paths.repo / str(source_path)).resolve()
|
|
48
|
+
if not path_repo.exists():
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
try:
|
|
52
|
+
paths = PackagePaths(path_repo)
|
|
53
|
+
except Exception as exception:
|
|
54
|
+
logger.warning(f'Failed to resolve editable source at "{path_repo}". Skipping. {exception!r}')
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
metadata = paths.metadata
|
|
58
|
+
if metadata.version_obj.prerelease and not self.versions.is_pre:
|
|
59
|
+
raise ValueError(
|
|
60
|
+
f'Editable dependency "{paths.name_ns}" is pre-release '
|
|
61
|
+
f'({metadata.version_obj.prerelease}) while "{self.paths.name_ns}" is release. Refusing to pin.'
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
editables[paths.name_ns] = metadata
|
|
65
|
+
editables[canonicalize_name(paths.name_ns)] = metadata
|
|
66
|
+
|
|
67
|
+
return editables
|
|
68
|
+
|
|
69
|
+
def _pin_editable(self, dep: str) -> str:
|
|
70
|
+
try:
|
|
71
|
+
requirement = Requirement(dep)
|
|
72
|
+
except InvalidRequirement:
|
|
73
|
+
return dep
|
|
74
|
+
|
|
75
|
+
if requirement.specifier:
|
|
76
|
+
return dep
|
|
77
|
+
if requirement.url:
|
|
78
|
+
return dep
|
|
79
|
+
|
|
80
|
+
metadata = self.editables.get(requirement.name)
|
|
81
|
+
if metadata is None:
|
|
82
|
+
metadata = self.editables.get(canonicalize_name(requirement.name))
|
|
83
|
+
if metadata is None:
|
|
84
|
+
return dep
|
|
85
|
+
|
|
86
|
+
extras = ""
|
|
87
|
+
if requirement.extras:
|
|
88
|
+
extras = f"[{','.join(sorted(requirement.extras))}]"
|
|
89
|
+
|
|
90
|
+
marker = ""
|
|
91
|
+
if requirement.marker:
|
|
92
|
+
marker = f"; {requirement.marker}"
|
|
93
|
+
|
|
94
|
+
pinned = f"{requirement.name}{extras}=={metadata.version}{marker}"
|
|
95
|
+
logger.info(f'Pinning editable dependency "{dep}" -> "{pinned}".')
|
|
96
|
+
return pinned
|
|
97
|
+
|
|
98
|
+
def _process_deps(self, deps: str|list[str]) -> str|list[str]:
|
|
99
|
+
|
|
100
|
+
if isinstance(deps, list):
|
|
101
|
+
deps=[self._process_deps(dep) for dep in deps]
|
|
102
|
+
deps=dedupe(deps)
|
|
103
|
+
return deps
|
|
104
|
+
|
|
105
|
+
dep=deps
|
|
106
|
+
dep=self._pin_editable(dep)
|
|
107
|
+
|
|
108
|
+
return dep
|
|
109
|
+
|
|
110
|
+
|
|
28
111
|
def apply(self) -> Path | list[Path] | None:
|
|
29
112
|
if not self.path.exists():
|
|
30
113
|
logger.info(f'pyproject.toml not found: "{self.path}". Skipping.')
|
|
@@ -43,6 +126,7 @@ class IncrementorPyproject(Incrementor):
|
|
|
43
126
|
self.path.write_toml(data)
|
|
44
127
|
return self.path
|
|
45
128
|
|
|
129
|
+
|
|
46
130
|
@property
|
|
47
131
|
def _author(self) -> str:
|
|
48
132
|
if self.paths.metadata.is_client:
|
|
@@ -106,36 +190,23 @@ class IncrementorPyproject(Incrementor):
|
|
|
106
190
|
values_resolved += resolve_values(value)
|
|
107
191
|
return values_resolved
|
|
108
192
|
|
|
109
|
-
|
|
193
|
+
|
|
110
194
|
extras = {key: dedupe(resolve_values(key)) for key in dependencies}
|
|
111
|
-
extras.pop("install",
|
|
195
|
+
install = extras.pop("install", [])
|
|
112
196
|
extras["all"] = dedupe(list(chain.from_iterable(extras.values())))
|
|
113
197
|
return install, extras
|
|
114
198
|
|
|
115
|
-
def _get_dependencies(self, data) -> dict[str, list[str]]:
|
|
116
|
-
table = data
|
|
117
|
-
for key in self.DEPENDENCIES_SECTION_PATH:
|
|
118
|
-
if key not in table:
|
|
119
|
-
return {}
|
|
120
|
-
table = table[key]
|
|
121
|
-
|
|
122
|
-
if table is None:
|
|
123
|
-
return {}
|
|
124
|
-
return {str(key): [str(value) for value in values] for key, values in table.items()}
|
|
125
199
|
|
|
126
200
|
def _enrich_toml(self, data):
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
if old != new:
|
|
130
|
-
logger.info(f'Incrementing version "{self.path}" {old} {Constants.ARROW_RIGHT} {new}...')
|
|
131
|
-
self.paths.metadata.version = str(new)
|
|
201
|
+
version = str(self.version)
|
|
202
|
+
logger.info(f'Applying release version "{version}" to "{self.path}"...')
|
|
132
203
|
|
|
133
204
|
metadata = ensure_table(data, ("tool", "corio", "metadata"))
|
|
134
|
-
metadata["version"] =
|
|
205
|
+
metadata["version"] = version
|
|
135
206
|
|
|
136
207
|
project = ensure_table(data, ("project",))
|
|
137
208
|
project["name"] = self.paths.name_ns
|
|
138
|
-
project["version"] =
|
|
209
|
+
project["version"] = version
|
|
139
210
|
project["description"] = self.paths.metadata.description
|
|
140
211
|
project["keywords"] = self.paths.metadata.keywords
|
|
141
212
|
project["readme"] = self.paths.readme.name
|
|
@@ -146,18 +217,32 @@ class IncrementorPyproject(Incrementor):
|
|
|
146
217
|
elif "license-files" in project:
|
|
147
218
|
del project["license-files"]
|
|
148
219
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
220
|
+
|
|
221
|
+
deps_corio = data.get("tool", {}).get("corio", {}).get("dependencies", None)
|
|
222
|
+
if deps_corio is not None:
|
|
223
|
+
install, extras = self._flatten_dependencies(deps_corio)
|
|
152
224
|
project["dependencies"] = install
|
|
153
225
|
project["optional-dependencies"] = extras
|
|
154
|
-
|
|
155
|
-
if "dev" in extras:
|
|
156
|
-
dependency_groups = ensure_table(data, ("dependency-groups",))
|
|
157
|
-
dependency_groups["dev"] = list(extras["dev"])
|
|
158
226
|
else:
|
|
159
227
|
logger.info(f'No dependencies section found in "{self.path}". Skipping dependency enrichment.')
|
|
160
228
|
|
|
229
|
+
|
|
230
|
+
deps = project.get("dependencies")
|
|
231
|
+
if deps is not None:
|
|
232
|
+
project["dependencies"] = self._process_deps(deps)
|
|
233
|
+
|
|
234
|
+
optionals = project.get("optional-dependencies")
|
|
235
|
+
if optionals is not None:
|
|
236
|
+
optionals = {
|
|
237
|
+
key: self._process_deps(values)
|
|
238
|
+
for key, values in optionals.items()
|
|
239
|
+
}
|
|
240
|
+
project["optional-dependencies"] = optionals
|
|
241
|
+
|
|
242
|
+
if "dev" in optionals:
|
|
243
|
+
dependency_groups = ensure_table(data, ("dependency-groups",))
|
|
244
|
+
dependency_groups["dev"] = list(optionals["dev"])
|
|
245
|
+
|
|
161
246
|
urls = ensure_table(project, ("urls",))
|
|
162
247
|
urls["Homepage"] = self.repo_url
|
|
163
248
|
|
|
@@ -187,11 +272,3 @@ class IncrementorPyproject(Incrementor):
|
|
|
187
272
|
del setuptools["script-files"]
|
|
188
273
|
|
|
189
274
|
return data
|
|
190
|
-
|
|
191
|
-
def _bump(self, version):
|
|
192
|
-
if self.versions.pinned:
|
|
193
|
-
return self.versions.pinned
|
|
194
|
-
|
|
195
|
-
if version.prerelease:
|
|
196
|
-
return version.bump_prerelease()
|
|
197
|
-
return version.bump_patch()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import shutil
|
|
2
|
+
import subprocess
|
|
2
3
|
from functools import cached_property
|
|
3
4
|
|
|
4
5
|
import build
|
|
@@ -17,7 +18,7 @@ from corio import https as https
|
|
|
17
18
|
from corio.constants import Constants
|
|
18
19
|
from corio.infra.project import Project
|
|
19
20
|
from corio.inherit import Inherit
|
|
20
|
-
from corio.logs import logger
|
|
21
|
+
from corio.logs import logger, sanitize
|
|
21
22
|
from corio.path import Path
|
|
22
23
|
|
|
23
24
|
|
|
@@ -47,6 +48,15 @@ class Releaser(Inherit[Project]):
|
|
|
47
48
|
if increment:
|
|
48
49
|
self.repo.fetch()
|
|
49
50
|
self.increment()
|
|
51
|
+
|
|
52
|
+
is_passed = self.tester.run()
|
|
53
|
+
if not is_passed:
|
|
54
|
+
if self.versions.is_pre:
|
|
55
|
+
logger.warning(f"Tests failed, but release is pre-release ({self.version.prerelease}). Continuing.")
|
|
56
|
+
else:
|
|
57
|
+
raise RuntimeError("Tests failed. Aborting release.")
|
|
58
|
+
|
|
59
|
+
if increment:
|
|
50
60
|
self.repo.push()
|
|
51
61
|
self.repo.fetch()
|
|
52
62
|
|
|
@@ -149,6 +159,7 @@ class Releaser(Inherit[Project]):
|
|
|
149
159
|
|
|
150
160
|
return IndexList[Incrementor](
|
|
151
161
|
[
|
|
162
|
+
IncrementorVersion(self),
|
|
152
163
|
IncrementorPyproject(self),
|
|
153
164
|
IncrementorHomeAssistantAddon(self),
|
|
154
165
|
IncrementorChangelog(self),
|
|
@@ -174,6 +185,10 @@ class Releaser(Inherit[Project]):
|
|
|
174
185
|
|
|
175
186
|
return releases
|
|
176
187
|
|
|
188
|
+
@cached_property
|
|
189
|
+
def tester(self):
|
|
190
|
+
return Tester(self)
|
|
191
|
+
|
|
177
192
|
def release(self):
|
|
178
193
|
for release in self.releases:
|
|
179
194
|
release.release()
|
|
@@ -200,6 +215,27 @@ class Incrementor(Inherit[Releaser]):
|
|
|
200
215
|
raise NotImplementedError
|
|
201
216
|
|
|
202
217
|
|
|
218
|
+
class IncrementorVersion(Incrementor):
|
|
219
|
+
@logger.instrument('Incrementing release version in-memory for "{self.paths.name_ns}"...')
|
|
220
|
+
def apply(self) -> Path | list[Path] | None:
|
|
221
|
+
old = self.versions.old
|
|
222
|
+
if self.versions.pinned:
|
|
223
|
+
new = self.versions.pinned
|
|
224
|
+
elif old.prerelease:
|
|
225
|
+
new = old.bump_prerelease()
|
|
226
|
+
else:
|
|
227
|
+
new = old.bump_patch()
|
|
228
|
+
|
|
229
|
+
if old != new:
|
|
230
|
+
logger.info(f'Incrementing runtime version {old} {Constants.ARROW_RIGHT} {new}...')
|
|
231
|
+
|
|
232
|
+
self.paths.metadata.version = str(new)
|
|
233
|
+
return None
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
|
|
203
239
|
class IncrementorHomeAssistantAddon(Incrementor):
|
|
204
240
|
DESC = 'Home Assistant Add-On config file'
|
|
205
241
|
|
|
@@ -529,3 +565,141 @@ class ReleaseDocumentation(Release):
|
|
|
529
565
|
|
|
530
566
|
with self.paths.repo.chdir:
|
|
531
567
|
self.deploy()
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
class Tester(Inherit[Releaser]):
|
|
571
|
+
TEST_FILENAME_PREFIX = "test_"
|
|
572
|
+
TEST_FILENAME_SUFFIX = ".py"
|
|
573
|
+
TOX_REQUIRES = ["tox>=4.22", "tox-uv>=1"]
|
|
574
|
+
|
|
575
|
+
@cached_property
|
|
576
|
+
def path_config_dir(self) -> Path:
|
|
577
|
+
return Path.temp() / f"{self.name}-tox"
|
|
578
|
+
|
|
579
|
+
@cached_property
|
|
580
|
+
def path_config(self) -> Path:
|
|
581
|
+
return self.path_config_dir / "tox.toml"
|
|
582
|
+
|
|
583
|
+
@cached_property
|
|
584
|
+
def dependencies(self) -> dict[str, list[str]]:
|
|
585
|
+
data = self.paths.pyproject_repo.read_toml()
|
|
586
|
+
table = data.get("tool", {}).get("corio", {}).get("dependencies", {})
|
|
587
|
+
dependencies = {
|
|
588
|
+
str(key): [str(value) for value in values]
|
|
589
|
+
for key, values in table.items()
|
|
590
|
+
if isinstance(values, list)
|
|
591
|
+
}
|
|
592
|
+
return dependencies
|
|
593
|
+
|
|
594
|
+
@cached_property
|
|
595
|
+
def modules(self) -> list[str]:
|
|
596
|
+
if not self.paths.tests.exists():
|
|
597
|
+
return []
|
|
598
|
+
|
|
599
|
+
modules = []
|
|
600
|
+
for path in sorted(self.paths.tests.glob(f"{self.TEST_FILENAME_PREFIX}*{self.TEST_FILENAME_SUFFIX}")):
|
|
601
|
+
module = path.stem.removeprefix(self.TEST_FILENAME_PREFIX)
|
|
602
|
+
if module:
|
|
603
|
+
modules.append(module)
|
|
604
|
+
return modules
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
def get_env(self, name: str, path_tests: Path, extras: list[str]) -> dict:
|
|
608
|
+
if path_tests.is_relative_to(self.paths.repo):
|
|
609
|
+
path_tests = path_tests.relative_to(self.paths.repo)
|
|
610
|
+
env = {
|
|
611
|
+
"description": f"Run {name} tests.",
|
|
612
|
+
"extras": extras,
|
|
613
|
+
"commands": [["python", "-m", "pytest", "-q", str(path_tests)]],
|
|
614
|
+
}
|
|
615
|
+
return env
|
|
616
|
+
|
|
617
|
+
@cached_property
|
|
618
|
+
def env(self) -> dict:
|
|
619
|
+
return self.get_env(name=self.paths.name_ns, path_tests=self.paths.tests, extras=["test"])
|
|
620
|
+
|
|
621
|
+
@cached_property
|
|
622
|
+
def envs(self) -> dict[str, dict]:
|
|
623
|
+
if not self.paths.metadata.test_envs:
|
|
624
|
+
if not self.modules:
|
|
625
|
+
return {}
|
|
626
|
+
return {self.paths.name_ns: self.env}
|
|
627
|
+
|
|
628
|
+
envs = {}
|
|
629
|
+
extras_available = set(self.dependencies.keys())
|
|
630
|
+
|
|
631
|
+
for module in self.modules:
|
|
632
|
+
extras = ["test"]
|
|
633
|
+
if module in extras_available:
|
|
634
|
+
extras.insert(0, module)
|
|
635
|
+
|
|
636
|
+
path_test = self.paths.tests / f"{self.TEST_FILENAME_PREFIX}{module}{self.TEST_FILENAME_SUFFIX}"
|
|
637
|
+
name = f"{self.paths.name_ns}.{module}"
|
|
638
|
+
envs[name] = self.get_env(name=name, path_tests=path_test, extras=extras)
|
|
639
|
+
|
|
640
|
+
return envs
|
|
641
|
+
|
|
642
|
+
@cached_property
|
|
643
|
+
def data(self) -> dict:
|
|
644
|
+
data = {
|
|
645
|
+
"requires": self.TOX_REQUIRES,
|
|
646
|
+
"env_list": list(self.envs.keys()),
|
|
647
|
+
"env": self.envs,
|
|
648
|
+
}
|
|
649
|
+
return data
|
|
650
|
+
|
|
651
|
+
def write_config(self):
|
|
652
|
+
self.path_config_dir.mkdir(parents=True, exist_ok=True)
|
|
653
|
+
self.path_config.write_toml(self.data)
|
|
654
|
+
|
|
655
|
+
def run_subprocess(self) -> int:
|
|
656
|
+
command = [
|
|
657
|
+
"uvx",
|
|
658
|
+
"--with",
|
|
659
|
+
"tox-uv",
|
|
660
|
+
"tox",
|
|
661
|
+
"-c",
|
|
662
|
+
str(self.path_config),
|
|
663
|
+
"--root",
|
|
664
|
+
str(self.paths.repo),
|
|
665
|
+
"--workdir",
|
|
666
|
+
str(self.paths.repo / ".tox"),
|
|
667
|
+
"run",
|
|
668
|
+
]
|
|
669
|
+
|
|
670
|
+
process = subprocess.Popen(
|
|
671
|
+
command,
|
|
672
|
+
cwd=self.paths.repo,
|
|
673
|
+
stdout=subprocess.PIPE,
|
|
674
|
+
stderr=subprocess.STDOUT,
|
|
675
|
+
text=True,
|
|
676
|
+
bufsize=1,
|
|
677
|
+
)
|
|
678
|
+
|
|
679
|
+
assert process.stdout is not None
|
|
680
|
+
for line in process.stdout:
|
|
681
|
+
logger.info(sanitize(line))
|
|
682
|
+
|
|
683
|
+
code = process.wait()
|
|
684
|
+
return code
|
|
685
|
+
|
|
686
|
+
@logger.instrument('Running test suite for "{self.paths.name_ns}"...')
|
|
687
|
+
def run(self) -> bool:
|
|
688
|
+
if not self.envs:
|
|
689
|
+
logger.warning(f'No tests found under "{self.paths.tests}". Skipping.')
|
|
690
|
+
return True
|
|
691
|
+
|
|
692
|
+
logger.info(f'Generating temporary tox config: "{self.path_config}"')
|
|
693
|
+
self.write_config()
|
|
694
|
+
try:
|
|
695
|
+
code = self.run_subprocess()
|
|
696
|
+
finally:
|
|
697
|
+
self.path_config.unlink(missing_ok=True)
|
|
698
|
+
shutil.rmtree(self.path_config_dir, ignore_errors=True)
|
|
699
|
+
|
|
700
|
+
if code == 0:
|
|
701
|
+
logger.info("All test environments passed.")
|
|
702
|
+
return True
|
|
703
|
+
|
|
704
|
+
logger.error(f"Test suite failed with exit code {code}.")
|
|
705
|
+
return False
|
|
@@ -6,7 +6,7 @@ from corio.docker import DockerClient
|
|
|
6
6
|
from corio.infra.project import Project
|
|
7
7
|
from corio.inherit import Inherit
|
|
8
8
|
from corio.iterator import IndexList
|
|
9
|
-
from corio.logs import logger
|
|
9
|
+
from corio.logs import logger, sanitize
|
|
10
10
|
from corio.merging import merge
|
|
11
11
|
from corio.path import Path, PackagePaths
|
|
12
12
|
|
|
@@ -114,7 +114,7 @@ class Stack(Inherit[Project]):
|
|
|
114
114
|
progress="plain",
|
|
115
115
|
stream_logs=True,
|
|
116
116
|
):
|
|
117
|
-
logger.info(line
|
|
117
|
+
logger.info(sanitize(line))
|
|
118
118
|
|
|
119
119
|
|
|
120
120
|
class Development(Stack):
|
|
@@ -177,8 +177,8 @@ class ProductionPublic(ProductionPrivate):
|
|
|
177
177
|
for tag in self.tags_public:
|
|
178
178
|
with logger.span(f'Pushing image "{tag}"'):
|
|
179
179
|
for tag, line_bytes in self.client.push(tag, stream_logs=True):
|
|
180
|
-
line = line_bytes.decode()
|
|
181
|
-
logger.info(line
|
|
180
|
+
line = line_bytes.decode()
|
|
181
|
+
logger.info(sanitize(line))
|
|
182
182
|
|
|
183
183
|
self
|
|
184
184
|
|
|
@@ -12,6 +12,16 @@ else:
|
|
|
12
12
|
|
|
13
13
|
LEVEL_DEFAULT = logging.DEBUG if env.IS_DEV else logging.INFO
|
|
14
14
|
|
|
15
|
+
|
|
16
|
+
def sanitize(message: str) -> str:
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
Sanitize a log line for brace-style formatters.
|
|
20
|
+
|
|
21
|
+
"""
|
|
22
|
+
return message.rstrip().replace("{", "{{").replace("}", "}}")
|
|
23
|
+
|
|
24
|
+
|
|
15
25
|
def get_logger(name, version=None, host=Constants.FMTR_OBS_HOST, key=None, org=Constants.ORG_NAME,
|
|
16
26
|
stream=STREAM_DEFAULT, environment=ENVIRONMENT_DEFAULT, level=LEVEL_DEFAULT):
|
|
17
27
|
"""
|
|
@@ -484,6 +484,7 @@ class Metadata:
|
|
|
484
484
|
|
|
485
485
|
is_pypi: bool = False
|
|
486
486
|
is_dockerhub: bool = False
|
|
487
|
+
test_envs: bool = False
|
|
487
488
|
|
|
488
489
|
@classmethod
|
|
489
490
|
def read(cls, path: Path) -> Self:
|
|
@@ -762,6 +763,15 @@ class PackagePaths(FromCallerMixin):
|
|
|
762
763
|
|
|
763
764
|
return self.repo / Constants.SCRIPTS_DIR
|
|
764
765
|
|
|
766
|
+
@property
|
|
767
|
+
def tests(self) -> Path:
|
|
768
|
+
"""
|
|
769
|
+
|
|
770
|
+
Path of package tests.
|
|
771
|
+
|
|
772
|
+
"""
|
|
773
|
+
return self.path / "tests"
|
|
774
|
+
|
|
765
775
|
def __repr__(self) -> str:
|
|
766
776
|
"""
|
|
767
777
|
|
|
@@ -5,7 +5,7 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[tool.corio.dependencies]
|
|
6
6
|
dev = ["logging", "version.dev", "debug", "sets", "yaml", "db.document", "infra"]
|
|
7
7
|
install = []
|
|
8
|
-
test = ["pytest-cov"]
|
|
8
|
+
test = ["pytest", "pytest-cov"]
|
|
9
9
|
yaml = ["yamlscript", "pyyaml"]
|
|
10
10
|
logging = ["logfire", "version"]
|
|
11
11
|
parallel = ["dask[bag]", "distributed", "bokeh"]
|
|
@@ -56,7 +56,7 @@ ha = ["env.io"]
|
|
|
56
56
|
"ha.api" = ["ha", "homeassistant_api", "aiohasupervisor"]
|
|
57
57
|
doc = ["mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav"]
|
|
58
58
|
youtube = ["pytubefix"]
|
|
59
|
-
infra = ["version.dev", "logging", "setup", "doc", "sets", "build", "twine", "packaging", "vcs", "docker.client", "merging", "http", "api", "tomlkit", "secrets", "cli"]
|
|
59
|
+
infra = ["version.dev", "logging", "setup", "doc", "sets", "build", "twine", "packaging", "vcs", "docker.client", "merging", "http", "api", "tomlkit", "secrets", "cli", "test"]
|
|
60
60
|
vcs = ["pygit2"]
|
|
61
61
|
tasmota = ["decode-config", "esptool"]
|
|
62
62
|
encrypt = ["pyrage"]
|
|
@@ -64,7 +64,7 @@ secrets = ["encrypt", "env.io", "yaml", "logging", "sets", "vcs"]
|
|
|
64
64
|
cli = ["sets", "logging"]
|
|
65
65
|
|
|
66
66
|
[tool.corio.metadata]
|
|
67
|
-
version = "2.2.
|
|
67
|
+
version = "2.2.2"
|
|
68
68
|
port = 0
|
|
69
69
|
base = "python"
|
|
70
70
|
description = "Collection of high-level tools to simplify everyday development tasks, with a focus on AI/ML"
|
|
@@ -77,6 +77,7 @@ services = []
|
|
|
77
77
|
keywords = []
|
|
78
78
|
is_pypi = true
|
|
79
79
|
is_dockerhub = false
|
|
80
|
+
test_envs = true
|
|
80
81
|
|
|
81
82
|
[tool.corio.metadata.setup]
|
|
82
83
|
|
|
@@ -93,7 +94,7 @@ corio = ["pyproject.package.toml"]
|
|
|
93
94
|
|
|
94
95
|
[project]
|
|
95
96
|
name = "corio"
|
|
96
|
-
version = "2.2.
|
|
97
|
+
version = "2.2.2"
|
|
97
98
|
description = "Collection of high-level tools to simplify everyday development tasks, with a focus on AI/ML"
|
|
98
99
|
readme = "README.md"
|
|
99
100
|
dependencies = []
|
|
@@ -102,8 +103,8 @@ license-files = ["LICENSE"]
|
|
|
102
103
|
keywords = []
|
|
103
104
|
|
|
104
105
|
[project.optional-dependencies]
|
|
105
|
-
dev = ["logfire", "semver", "pydevd-pycharm~=251.25410.159", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "beanie", "setuptools", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav", "build", "twine", "packaging", "pygit2", "python-on-whales", "deepmerge", "httpx", "httpx_retries", "logfire[httpx]", "fastapi", "uvicorn[standard]", "logfire[fastapi]", "tomlkit", "pyrage", "dotenv"]
|
|
106
|
-
test = ["pytest-cov"]
|
|
106
|
+
dev = ["logfire", "semver", "pydevd-pycharm~=251.25410.159", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "beanie", "setuptools", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav", "build", "twine", "packaging", "pygit2", "python-on-whales", "deepmerge", "httpx", "httpx_retries", "logfire[httpx]", "fastapi", "uvicorn[standard]", "logfire[fastapi]", "tomlkit", "pyrage", "dotenv", "pytest", "pytest-cov"]
|
|
107
|
+
test = ["pytest", "pytest-cov"]
|
|
107
108
|
yaml = ["yamlscript", "pyyaml"]
|
|
108
109
|
logging = ["logfire"]
|
|
109
110
|
parallel = ["dask[bag]", "distributed", "bokeh"]
|
|
@@ -154,13 +155,13 @@ ha = ["dotenv"]
|
|
|
154
155
|
"ha.api" = ["dotenv", "homeassistant_api", "aiohasupervisor"]
|
|
155
156
|
doc = ["mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav"]
|
|
156
157
|
youtube = ["pytubefix"]
|
|
157
|
-
infra = ["semver", "logfire", "setuptools", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "build", "twine", "packaging", "pygit2", "python-on-whales", "deepmerge", "httpx", "httpx_retries", "logfire[httpx]", "fastapi", "uvicorn[standard]", "logfire[fastapi]", "tomlkit", "pyrage", "dotenv"]
|
|
158
|
+
infra = ["semver", "logfire", "setuptools", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "build", "twine", "packaging", "pygit2", "python-on-whales", "deepmerge", "httpx", "httpx_retries", "logfire[httpx]", "fastapi", "uvicorn[standard]", "logfire[fastapi]", "tomlkit", "pyrage", "dotenv", "pytest", "pytest-cov"]
|
|
158
159
|
vcs = ["pygit2"]
|
|
159
160
|
tasmota = ["decode-config", "esptool"]
|
|
160
161
|
encrypt = ["pyrage"]
|
|
161
162
|
secrets = ["pyrage", "dotenv", "yamlscript", "pyyaml", "logfire", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "pygit2"]
|
|
162
163
|
cli = ["pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "logfire"]
|
|
163
|
-
all = ["logfire", "semver", "pydevd-pycharm~=251.25410.159", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "beanie", "setuptools", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav", "build", "twine", "packaging", "pygit2", "python-on-whales", "deepmerge", "httpx", "httpx_retries", "logfire[httpx]", "fastapi", "uvicorn[standard]", "logfire[fastapi]", "tomlkit", "pyrage", "dotenv", "pytest-cov", "dask[bag]", "distributed", "bokeh", "tokenizers", "faker", "sre_yield", "contexttimer", "Unidecode", "tinynetrc", "huggingface_hub", "peft", "transformers[sentencepiece]", "torchvision", "torchaudio", "cuda-bindings==13.2.0", "cuda-pathfinder==1.5.4", "cuda-toolkit==13.0.2", "nvidia-cublas==13.1.0.3", "nvidia-cuda-cupti==13.0.85", "nvidia-cuda-nvrtc==13.0.88", "nvidia-cuda-runtime==13.0.96", "nvidia-cudnn-cu13==9.19.0.56", "nvidia-cufft==12.0.0.61", "nvidia-cufile==1.15.1.6", "nvidia-curand==10.4.0.35", "nvidia-cusolver==12.0.4.66", "nvidia-cusparse==12.6.3.3", "nvidia-cusparselt-cu13==0.8.0", "nvidia-nccl-cu13==2.28.9", "nvidia-nvjitlink==13.0.88", "nvidia-nvshmem-cu13==3.4.5", "nvidia-nvtx==13.0.85", "torch==2.11.0", "triton==3.6.0", "openai", "pydantic-ai-slim[logfire,openai]", "ollama", "json_repair", "sentence_transformers", "pandas", "tabulate", "openpyxl", "odfpy", "deepdiff", "html2text", "flet[all] <0.80.0", "flet-video", "flet-webview", "google-auth", "google-auth-oauthlib", "google-auth-httplib2", "google-api-python-client", "diskcache", "cachetools", "pymupdf", "pymupdf4llm", "appdirs", "filetype", "dnspython[doh]", "regex", "playwright", "aiomqtt", "av", "homeassistant_api", "aiohasupervisor", "pytubefix", "decode-config", "esptool"]
|
|
164
|
+
all = ["logfire", "semver", "pydevd-pycharm~=251.25410.159", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "beanie", "setuptools", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav", "build", "twine", "packaging", "pygit2", "python-on-whales", "deepmerge", "httpx", "httpx_retries", "logfire[httpx]", "fastapi", "uvicorn[standard]", "logfire[fastapi]", "tomlkit", "pyrage", "dotenv", "pytest", "pytest-cov", "dask[bag]", "distributed", "bokeh", "tokenizers", "faker", "sre_yield", "contexttimer", "Unidecode", "tinynetrc", "huggingface_hub", "peft", "transformers[sentencepiece]", "torchvision", "torchaudio", "cuda-bindings==13.2.0", "cuda-pathfinder==1.5.4", "cuda-toolkit==13.0.2", "nvidia-cublas==13.1.0.3", "nvidia-cuda-cupti==13.0.85", "nvidia-cuda-nvrtc==13.0.88", "nvidia-cuda-runtime==13.0.96", "nvidia-cudnn-cu13==9.19.0.56", "nvidia-cufft==12.0.0.61", "nvidia-cufile==1.15.1.6", "nvidia-curand==10.4.0.35", "nvidia-cusolver==12.0.4.66", "nvidia-cusparse==12.6.3.3", "nvidia-cusparselt-cu13==0.8.0", "nvidia-nccl-cu13==2.28.9", "nvidia-nvjitlink==13.0.88", "nvidia-nvshmem-cu13==3.4.5", "nvidia-nvtx==13.0.85", "torch==2.11.0", "triton==3.6.0", "openai", "pydantic-ai-slim[logfire,openai]", "ollama", "json_repair", "sentence_transformers", "pandas", "tabulate", "openpyxl", "odfpy", "deepdiff", "html2text", "flet[all] <0.80.0", "flet-video", "flet-webview", "google-auth", "google-auth-oauthlib", "google-auth-httplib2", "google-api-python-client", "diskcache", "cachetools", "pymupdf", "pymupdf4llm", "appdirs", "filetype", "dnspython[doh]", "regex", "playwright", "aiomqtt", "av", "homeassistant_api", "aiohasupervisor", "pytubefix", "decode-config", "esptool"]
|
|
164
165
|
|
|
165
166
|
[[project.authors]]
|
|
166
167
|
name = "Frontmatter AI"
|
|
@@ -173,4 +174,4 @@ Homepage = "https://github.com/fmtr/corio"
|
|
|
173
174
|
corio = "corio.entrypoint:main"
|
|
174
175
|
|
|
175
176
|
[dependency-groups]
|
|
176
|
-
dev = ["logfire", "semver", "pydevd-pycharm~=251.25410.159", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "beanie", "setuptools", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav", "build", "twine", "packaging", "pygit2", "python-on-whales", "deepmerge", "httpx", "httpx_retries", "logfire[httpx]", "fastapi", "uvicorn[standard]", "logfire[fastapi]", "tomlkit", "pyrage", "dotenv"]
|
|
177
|
+
dev = ["logfire", "semver", "pydevd-pycharm~=251.25410.159", "pydantic-settings", "pydantic", "pydantic-extra-types", "pycountry", "yamlscript", "pyyaml", "beanie", "setuptools", "mkdocs", "mkdocs-material", "mkdocstrings[python]", "mike", "mkdocs-include-dir-to-nav", "build", "twine", "packaging", "pygit2", "python-on-whales", "deepmerge", "httpx", "httpx_retries", "logfire[httpx]", "fastapi", "uvicorn[standard]", "logfire[fastapi]", "tomlkit", "pyrage", "dotenv", "pytest", "pytest-cov"]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from contextlib import nullcontext
|
|
2
|
+
|
|
3
|
+
import corio.caching as caching_module
|
|
4
|
+
from corio.caching import Disk, TLRU
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_disk_nested_dump(tmp_path):
|
|
8
|
+
cache = Disk(tmp_path / "cache")
|
|
9
|
+
|
|
10
|
+
cache.setdefault("svc", Disk)["enabled"] = True
|
|
11
|
+
cache["count"] = 2
|
|
12
|
+
|
|
13
|
+
dumped = cache.dump()
|
|
14
|
+
assert dumped["count"] == 2
|
|
15
|
+
assert dumped["svc"]["enabled"] is True
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_tlru_expire_with_custom_timer(monkeypatch):
|
|
19
|
+
class DummyLogger:
|
|
20
|
+
@staticmethod
|
|
21
|
+
def span(_):
|
|
22
|
+
return nullcontext()
|
|
23
|
+
|
|
24
|
+
@staticmethod
|
|
25
|
+
def debug(_):
|
|
26
|
+
return None
|
|
27
|
+
|
|
28
|
+
monkeypatch.setattr(caching_module, "logger", DummyLogger())
|
|
29
|
+
|
|
30
|
+
now = [0]
|
|
31
|
+
cache = TLRU(maxsize=4, timer=lambda: now[0], ttu_static=5, desc="test")
|
|
32
|
+
cache["k1"] = "v1"
|
|
33
|
+
|
|
34
|
+
assert "k1" in cache
|
|
35
|
+
now[0] = 6
|
|
36
|
+
expired = cache.expire()
|
|
37
|
+
|
|
38
|
+
assert expired == [("k1", "v1")]
|
|
39
|
+
assert "k1" not in cache
|