toml-repo 0.1.2__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.
toml_repo/__init__.py ADDED
@@ -0,0 +1,19 @@
1
+ """
2
+ The toml_repo package provides a generic TOML-based repository manager.
3
+
4
+ It handles finding, loading, merging, and searching TOML configuration repositories
5
+ with support for multiple URL schemes (file://, pkg://, http://), import resolution,
6
+ and precedence-based configuration merging.
7
+ """
8
+
9
+ from .manager import RepoManager
10
+ from .repo import REPO_REF, Repo, get_config_suffix, set_config_suffix, set_pkg_resource_root
11
+
12
+ __all__ = [
13
+ "RepoManager",
14
+ "Repo",
15
+ "get_config_suffix",
16
+ "set_config_suffix",
17
+ "set_pkg_resource_root",
18
+ "REPO_REF",
19
+ ]
@@ -0,0 +1,5 @@
1
+ from requests_cache import CachedSession
2
+
3
+ # We use this cache so that if the client is offline all previously downloaded repos will
4
+ # still keep working.
5
+ http_session = CachedSession(stale_if_error=True, use_cache_dir=True)
toml_repo/manager.py ADDED
@@ -0,0 +1,141 @@
1
+ """
2
+ Manages the repository of TOML-based processing recipes and configurations.
3
+ """
4
+
5
+ # pyright: reportImportCycles=false
6
+ # The circular dependency between manager.py and repo.py is properly handled
7
+ # using TYPE_CHECKING and local imports where needed.
8
+
9
+ from __future__ import annotations
10
+
11
+ import logging
12
+ from typing import TYPE_CHECKING, Any, overload
13
+
14
+ from multidict import MultiDict
15
+
16
+ if TYPE_CHECKING:
17
+ from toml_repo.repo import Repo
18
+
19
+
20
+ class RepoManager:
21
+ """
22
+ Manages the collection of TOML repositories.
23
+
24
+ This class is responsible for finding, loading, and providing an API
25
+ for searching through known repositories defined in TOML configuration files.
26
+ """
27
+
28
+ def __init__(self):
29
+ """
30
+ Initializes the RepoManager.
31
+ """
32
+ self.repos: list[Repo] = []
33
+
34
+ # Most users will just want to read from merged
35
+ self.merged: MultiDict[Any] = MultiDict()
36
+
37
+ @property
38
+ def regular_repos(self) -> list[Repo]:
39
+ "We exclude certain repo types (preferences, recipe) from the list of repos users care about."
40
+ return [
41
+ r
42
+ for r in self.repos
43
+ if r.kind() not in ["preferences", "recipe"] and not r.is_scheme("pkg")
44
+ ]
45
+
46
+ def add_repo(self, url: str) -> Repo:
47
+ from toml_repo.repo import Repo # Local import to avoid circular dependency
48
+
49
+ logging.debug(f"Adding repo: {url}")
50
+ r = Repo(url)
51
+ self.repos.append(r)
52
+
53
+ # FIXME, generate the merged dict lazily
54
+ self._add_merged(r)
55
+
56
+ # if this new repo has sub-repos, add them too
57
+ r.add_by_repo_refs(self)
58
+
59
+ return r
60
+
61
+ def get_repo_by_url(self, url: str) -> Repo | None:
62
+ """
63
+ Retrieves a repository by its URL.
64
+
65
+ Args:
66
+ url: The URL of the repository to retrieve.
67
+
68
+ Returns:
69
+ The Repo instance with the matching URL, or None if not found.
70
+ """
71
+ for repo in self.repos:
72
+ if repo.url == url:
73
+ return repo
74
+ return None
75
+
76
+ def get_repo_by_kind(self, kind: str) -> Repo | None:
77
+ """
78
+ Retrieves the first repository matching the specified kind.
79
+
80
+ Args:
81
+ kind: The kind of repository to search for (e.g., "recipe", "preferences").
82
+
83
+ Returns:
84
+ The first Repo instance matching the kind, or None if not found.
85
+ """
86
+ for repo in self.repos:
87
+ if repo.kind() == kind:
88
+ return repo
89
+ return None
90
+
91
+ # If a default was provided use that type for return
92
+ @overload
93
+ def get[T](self, key: str, default: T) -> T | Any: ...
94
+
95
+ @overload
96
+ def get(self, key: str, default: None = None) -> Any | None: ...
97
+
98
+ def get[T](self, key: str, default: T | None = None) -> T | Any | None:
99
+ """
100
+ Searches for a key across all repositories and returns the first value found.
101
+ The search is performed in reverse order of repository loading, so the
102
+ most recently added repositories have precedence.
103
+
104
+ Args:
105
+ key: The dot-separated key to search for (e.g., "repo.kind").
106
+ default: The value to return if the key is not found in any repo.
107
+
108
+ Returns:
109
+ The found value or the default.
110
+ """
111
+ # Iterate in reverse to give precedence to later-loaded repos
112
+ for repo in reversed(self.repos):
113
+ value = repo.get(key)
114
+ if value is not None:
115
+ return value
116
+
117
+ return default
118
+
119
+ def dump(self):
120
+ """
121
+ Prints a detailed, multi-line description of the combined top-level keys
122
+ and values from all repositories, using a MultiDict for aggregation.
123
+ This is useful for debugging and inspecting the consolidated configuration.
124
+ """
125
+
126
+ combined_config = self.merged
127
+ logging.info("RepoManager Dump")
128
+ for key, value in combined_config.items():
129
+ # tomlkit.items() can return complex types (e.g., ArrayOfTables, Table)
130
+ # For a debug dump, a simple string representation is usually sufficient.
131
+ logging.info(" %s: %s", key, value)
132
+
133
+ def _add_merged(self, repo: Repo) -> None:
134
+ for key, value in repo.config.items():
135
+ self.merged.add(key, value)
136
+
137
+ def __str__(self):
138
+ lines = [f"RepoManager with {len(self.repos)} repositories:"]
139
+ for i, repo in enumerate(self.repos):
140
+ lines.append(f" [{i}] {repo.url}")
141
+ return "\n".join(lines)
toml_repo/py.typed ADDED
@@ -0,0 +1 @@
1
+ py.typed