py-rattler 0.22.0__cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.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.
Files changed (68) hide show
  1. py_rattler-0.22.0.dist-info/METADATA +208 -0
  2. py_rattler-0.22.0.dist-info/RECORD +68 -0
  3. py_rattler-0.22.0.dist-info/WHEEL +4 -0
  4. rattler/__init__.py +114 -0
  5. rattler/channel/__init__.py +5 -0
  6. rattler/channel/channel.py +94 -0
  7. rattler/channel/channel_config.py +43 -0
  8. rattler/channel/channel_priority.py +14 -0
  9. rattler/exceptions.py +120 -0
  10. rattler/explicit_environment/__init__.py +3 -0
  11. rattler/explicit_environment/environment.py +69 -0
  12. rattler/index/__init__.py +3 -0
  13. rattler/index/index.py +112 -0
  14. rattler/install/__init__.py +3 -0
  15. rattler/install/installer.py +96 -0
  16. rattler/lock/__init__.py +23 -0
  17. rattler/lock/channel.py +52 -0
  18. rattler/lock/environment.py +213 -0
  19. rattler/lock/hash.py +33 -0
  20. rattler/lock/lock_file.py +118 -0
  21. rattler/lock/package.py +302 -0
  22. rattler/match_spec/__init__.py +4 -0
  23. rattler/match_spec/match_spec.py +294 -0
  24. rattler/match_spec/nameless_match_spec.py +185 -0
  25. rattler/networking/__init__.py +21 -0
  26. rattler/networking/client.py +74 -0
  27. rattler/networking/fetch_repo_data.py +103 -0
  28. rattler/networking/middleware.py +234 -0
  29. rattler/package/__init__.py +26 -0
  30. rattler/package/about_json.py +329 -0
  31. rattler/package/index_json.py +437 -0
  32. rattler/package/no_arch_type.py +142 -0
  33. rattler/package/package_name.py +204 -0
  34. rattler/package/package_name_matcher.py +81 -0
  35. rattler/package/paths_json.py +696 -0
  36. rattler/package/run_exports_json.py +268 -0
  37. rattler/package_streaming/__init__.py +26 -0
  38. rattler/platform/__init__.py +4 -0
  39. rattler/platform/arch.py +59 -0
  40. rattler/platform/platform.py +217 -0
  41. rattler/prefix/__init__.py +4 -0
  42. rattler/prefix/prefix_paths.py +442 -0
  43. rattler/prefix/prefix_record.py +234 -0
  44. rattler/pty/__init__.py +25 -0
  45. rattler/pty/pty_process.py +391 -0
  46. rattler/pty/pty_session.py +241 -0
  47. rattler/py.typed +0 -0
  48. rattler/rattler.abi3.so +0 -0
  49. rattler/repo_data/__init__.py +19 -0
  50. rattler/repo_data/gateway.py +337 -0
  51. rattler/repo_data/package_record.py +938 -0
  52. rattler/repo_data/patch_instructions.py +22 -0
  53. rattler/repo_data/record.py +164 -0
  54. rattler/repo_data/repo_data.py +74 -0
  55. rattler/repo_data/source.py +85 -0
  56. rattler/repo_data/sparse.py +356 -0
  57. rattler/shell/__init__.py +3 -0
  58. rattler/shell/shell.py +134 -0
  59. rattler/solver/__init__.py +3 -0
  60. rattler/solver/solver.py +220 -0
  61. rattler/utils/rattler_version.py +19 -0
  62. rattler/version/__init__.py +5 -0
  63. rattler/version/version.py +591 -0
  64. rattler/version/version_spec.py +184 -0
  65. rattler/version/with_source.py +80 -0
  66. rattler/virtual_package/__init__.py +4 -0
  67. rattler/virtual_package/generic.py +136 -0
  68. rattler/virtual_package/virtual_package.py +201 -0
@@ -0,0 +1,294 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from rattler.channel.channel import Channel
6
+ from rattler.package.package_name_matcher import PackageNameMatcher
7
+ from rattler.rattler import PyMatchSpec
8
+
9
+ if TYPE_CHECKING:
10
+ from rattler.match_spec import NamelessMatchSpec
11
+ from rattler.repo_data import PackageRecord
12
+
13
+
14
+ class MatchSpec:
15
+ """
16
+ A `MatchSpec` is a query language for conda packages.
17
+ It can be composed of any of the attributes of `PackageRecord`.
18
+
19
+ `MatchSpec` can be composed of keyword arguments, where keys are
20
+ any of the attributes of `PackageRecord`. Values for keyword arguments
21
+ are exact values the attributes should match against. Many fields can
22
+ be matched against non-exact values by including wildcard `*` and `>`/`<`
23
+ ranges where supported. Any non-specified field is the equivalent of a
24
+ full wildcard match.
25
+
26
+ MatchSpecs can also be composed using a single positional argument, with optional
27
+ keyword arguments. Keyword arguments also override any conflicting information
28
+ provided in the positional argument. Conda has historically had several string
29
+ representations for equivalent MatchSpecs.
30
+
31
+ A series of rules are now followed for creating the canonical string
32
+ representation of a MatchSpec instance. The canonical string representation can
33
+ generically be represented by:
34
+
35
+ `(channel(/subdir):(namespace):)name(version(build))[key1=value1,key2=value2]`
36
+
37
+ where `()` indicate optional fields.
38
+
39
+ The rules for constructing a canonical string representation are:
40
+
41
+ 1. `name` (i.e. "package name") is required, but its value can be '*'. Its
42
+ position is always outside the key-value brackets.
43
+ It can also be a glob pattern or a regex if `exact_names_only` is `False`.
44
+ 2. If `version` is an exact version, it goes outside the key-value brackets and
45
+ is prepended by `==`. If `version` is a "fuzzy" value (e.g. `1.11.*`), it goes
46
+ outside the key-value brackets with the `.*` left off and is prepended by `=`.
47
+ Otherwise `version` is included inside key-value brackets.
48
+ 3. If `version` is an exact version, and `build` is an exact value, `build` goes
49
+ outside key-value brackets prepended by a `=`. Otherwise, `build` goes inside
50
+ key-value brackets. `build_string` is an alias for `build`.
51
+ 4. The `namespace` position is being held for a future feature. It is currently
52
+ ignored.
53
+ 5. If `channel` is included and is an exact value, a `::` separator is used between
54
+ `channel` and `name`. `channel` can either be a canonical channel name or a
55
+ channel url. In the canonical string representation, the canonical channel name
56
+ will always be used.
57
+ 6. If `channel` is an exact value and `subdir` is an exact value, `subdir` is
58
+ appended to `channel` with a `/` separator. Otherwise, `subdir` is included in
59
+ the key-value brackets.
60
+ 7. Key-value brackets can be delimited by comma, space, or comma+space. Value can
61
+ optionally be wrapped in single or double quotes, but must be wrapped if `value`
62
+ contains a comma, space, or equal sign. The canonical format uses comma delimiters
63
+ and single quotes.
64
+ 8. When constructing a `MatchSpec` instance from a string, any key-value pair given
65
+ inside the key-value brackets overrides any matching parameter given outside the
66
+ brackets.
67
+
68
+ When `MatchSpec` attribute values are simple strings, the are interpreted using the
69
+ following conventions:
70
+ - If the string begins with `^` and ends with `$`, it is converted to a regex.
71
+ - If the string contains an asterisk (`*`), it is transformed from a glob to a
72
+ regex.
73
+ - Otherwise, an exact match to the string is sought.
74
+
75
+ To fully-specify a package with a full, exact spec, the following fields must be
76
+ given as exact values:
77
+ - channel
78
+ - subdir
79
+ - name
80
+ - version
81
+ - build
82
+ """
83
+
84
+ def __init__(
85
+ self,
86
+ spec: str,
87
+ strict: bool = False,
88
+ exact_names_only: bool = True,
89
+ experimental_extras: bool = False,
90
+ experimental_conditionals: bool = False,
91
+ ) -> None:
92
+ """
93
+ Create a new version spec.
94
+
95
+ When `strict` is `True`, some ambiguous version specs are rejected.
96
+
97
+ When `experimental_extras` is `True`, extras syntax is enabled (e.g., `pkg[extras=[foo,bar]]`).
98
+
99
+ When `experimental_conditionals` is `True`, conditionals syntax is enabled (e.g., `pkg; if python >=3.6`).
100
+
101
+ ```python
102
+ >>> MatchSpec("pip >=24.0")
103
+ MatchSpec("pip >=24.0")
104
+ >>> MatchSpec("pip 24")
105
+ MatchSpec("pip ==24")
106
+ >>> MatchSpec("python[license=MIT]")
107
+ MatchSpec("python[license="MIT"]")
108
+ >>> MatchSpec("foo*", strict=True, exact_names_only=False)
109
+ MatchSpec("foo*")
110
+ >>> MatchSpec("^foo.*$", strict=True, exact_names_only=True) # doctest: +IGNORE_EXCEPTION_DETAIL
111
+ Traceback (most recent call last):
112
+ InvalidMatchSpecException: "^foo.*$" looks like a regex but only exact package names are allowed, package names can only contain 0-9, a-z, A-Z, -, _, or .
113
+ >>>
114
+ ```
115
+ """
116
+ if isinstance(spec, str):
117
+ self._match_spec = PyMatchSpec(
118
+ spec, strict, exact_names_only, experimental_extras, experimental_conditionals
119
+ )
120
+ else:
121
+ raise TypeError(
122
+ f"MatchSpec constructor received unsupported type {type(spec).__name__!r} for the 'spec' parameter"
123
+ )
124
+
125
+ @property
126
+ def name(self) -> Optional[PackageNameMatcher]:
127
+ """
128
+ The name of the package.
129
+ """
130
+ return PackageNameMatcher._from_py_package_name_matcher(self._match_spec.name)
131
+
132
+ @property
133
+ def version(self) -> Optional[str]:
134
+ """
135
+ The version spec of the package (e.g. `1.2.3`, `>=1.2.3`, `1.2.*`)
136
+ """
137
+ return self._match_spec.version
138
+
139
+ @property
140
+ def build(self) -> Optional[str]:
141
+ """
142
+ The build string of the package (e.g. `py37_0`, `py37h6de7cb9_0`, `py*`)
143
+ """
144
+ return self._match_spec.build
145
+
146
+ @property
147
+ def build_number(self) -> Optional[str]:
148
+ """
149
+ The build number of the package.
150
+ """
151
+ return self._match_spec.build_number
152
+
153
+ @property
154
+ def file_name(self) -> Optional[str]:
155
+ """
156
+ Match the specific filename of the package.
157
+ """
158
+ return self._match_spec.file_name
159
+
160
+ @property
161
+ def channel(self) -> Optional[Channel]:
162
+ """
163
+ The channel of the package.
164
+ """
165
+ channel = self._match_spec.channel
166
+ return channel and Channel._from_py_channel(channel)
167
+
168
+ @property
169
+ def subdir(self) -> Optional[str]:
170
+ """
171
+ The subdir of the channel.
172
+ """
173
+ return self._match_spec.subdir
174
+
175
+ @property
176
+ def namespace(self) -> Optional[str]:
177
+ """
178
+ The namespace of the package.
179
+ """
180
+ return self._match_spec.namespace
181
+
182
+ @property
183
+ def extras(self) -> Optional[list[str]]:
184
+ """
185
+ The extras (optional dependencies) of the package.
186
+ """
187
+ return self._match_spec.extras
188
+
189
+ @property
190
+ def condition(self) -> Optional[str]:
191
+ """
192
+ The condition under which this match spec applies.
193
+ """
194
+ return self._match_spec.condition
195
+
196
+ @property
197
+ def md5(self) -> Optional[bytes]:
198
+ """
199
+ The md5 hash of the package.
200
+ """
201
+ return self._match_spec.md5
202
+
203
+ @property
204
+ def sha256(self) -> Optional[bytes]:
205
+ """
206
+ The sha256 hash of the package.
207
+ """
208
+ return self._match_spec.sha256
209
+
210
+ @classmethod
211
+ def _from_py_match_spec(cls, py_match_spec: PyMatchSpec) -> MatchSpec:
212
+ """
213
+ Construct py-rattler MatchSpec from PyMatchSpec FFI object.
214
+ """
215
+ match_spec = cls.__new__(cls)
216
+ match_spec._match_spec = py_match_spec
217
+
218
+ return match_spec
219
+
220
+ def matches(self, record: PackageRecord) -> bool:
221
+ """Match a MatchSpec against a PackageRecord."""
222
+ return self._match_spec.matches(record._record)
223
+
224
+ @classmethod
225
+ def from_nameless(cls, spec: NamelessMatchSpec, name: str) -> MatchSpec:
226
+ """
227
+ Constructs a MatchSpec from a NamelessMatchSpec
228
+ and a name.
229
+
230
+ Examples
231
+ --------
232
+ ```python
233
+ >>> from rattler import NamelessMatchSpec
234
+ >>> spec = NamelessMatchSpec('3.4')
235
+ >>> MatchSpec.from_nameless(spec, "foo")
236
+ MatchSpec("foo ==3.4")
237
+ >>> MatchSpec.from_nameless(spec, "$foo") # doctest: +IGNORE_EXCEPTION_DETAIL
238
+ Traceback (most recent call last):
239
+ exceptions.PackageNameMatcherParseException
240
+ >>>
241
+ ```
242
+ """
243
+ return cls._from_py_match_spec(PyMatchSpec.from_nameless(spec._nameless_match_spec, name))
244
+
245
+ @classmethod
246
+ def from_url(cls, url: str) -> MatchSpec:
247
+ """
248
+ Constructs a MatchSpec from a URL.
249
+
250
+ Examples
251
+ --------
252
+ ```python
253
+ >>> MatchSpec.from_url('https://repo.anaconda.com/pkgs/main/linux-64/python-3.9.0-h3.tar.bz2')
254
+ MatchSpec("python[url="https://repo.anaconda.com/pkgs/main/linux-64/python-3.9.0-h3.tar.bz2"]")
255
+ >>> MatchSpec.from_url('https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#d7c89558ba9fa0495403155b64376d81')
256
+ MatchSpec("_libgcc_mutex[md5="d7c89558ba9fa0495403155b64376d81", url="https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"]")
257
+ >>> MatchSpec.from_url('https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2#sha256:adfa71f158cbd872a36394c56c3568e6034aa55c623634b37a4836bd036e6b91')
258
+ MatchSpec("_libgcc_mutex[sha256="adfa71f158cbd872a36394c56c3568e6034aa55c623634b37a4836bd036e6b91", url="https://conda.anaconda.org/conda-forge/linux-64/_libgcc_mutex-0.1-conda_forge.tar.bz2"]")
259
+ >>>
260
+ ```
261
+ """
262
+ return cls._from_py_match_spec(PyMatchSpec.from_url(url))
263
+
264
+ def __str__(self) -> str:
265
+ """
266
+ Returns a string representation of the MatchSpec.
267
+
268
+ Examples
269
+ --------
270
+ ```python
271
+ >>> from rattler import NamelessMatchSpec
272
+ >>> spec = NamelessMatchSpec('3.4')
273
+ >>> str(MatchSpec.from_nameless(spec, "foo"))
274
+ 'foo ==3.4'
275
+ >>>
276
+ ```
277
+ """
278
+ return self._match_spec.as_str()
279
+
280
+ def __repr__(self) -> str:
281
+ """
282
+ Returns a representation of the MatchSpec.
283
+
284
+ Examples
285
+ --------
286
+ ```python
287
+ >>> from rattler import NamelessMatchSpec
288
+ >>> spec = NamelessMatchSpec('3.4')
289
+ >>> MatchSpec.from_nameless(spec, "foo")
290
+ MatchSpec("foo ==3.4")
291
+ >>>
292
+ ```
293
+ """
294
+ return f'MatchSpec("{self._match_spec.as_str()}")'
@@ -0,0 +1,185 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Optional
3
+ from rattler.channel.channel import Channel
4
+
5
+ from rattler.rattler import PyNamelessMatchSpec
6
+
7
+ if TYPE_CHECKING:
8
+ from rattler.match_spec import MatchSpec
9
+ from rattler.repo_data import PackageRecord
10
+
11
+
12
+ class NamelessMatchSpec:
13
+ """
14
+ Similar to a `MatchSpec` but does not include the package name.
15
+ This is useful in places where the package name is already known
16
+ (e.g. `foo = "3.4.1 *cuda"`).
17
+ """
18
+
19
+ def __init__(
20
+ self,
21
+ spec: str,
22
+ strict: bool = False,
23
+ experimental_extras: bool = False,
24
+ experimental_conditionals: bool = False,
25
+ ) -> None:
26
+ """
27
+ Create a new version spec.
28
+
29
+ When `strict` is `True`, some ambiguous version specs are rejected.
30
+
31
+ When `experimental_extras` is `True`, extras syntax is enabled (e.g., `[extras=[foo,bar]]`).
32
+
33
+ When `experimental_conditionals` is `True`, conditionals syntax is enabled (e.g., `>=1.0; if python >=3.6`).
34
+
35
+ ```python
36
+ >>> NamelessMatchSpec(">=24.0")
37
+ NamelessMatchSpec(">=24.0")
38
+ >>> NamelessMatchSpec("24")
39
+ NamelessMatchSpec("==24")
40
+ >>>
41
+ ```
42
+ """
43
+ if isinstance(spec, str):
44
+ self._nameless_match_spec = PyNamelessMatchSpec(
45
+ spec, strict, experimental_extras, experimental_conditionals
46
+ )
47
+ else:
48
+ raise TypeError(
49
+ "NamelessMatchSpec constructor received unsupported type"
50
+ f" {type(spec).__name__!r} for the 'spec' parameter"
51
+ )
52
+
53
+ @property
54
+ def version(self) -> Optional[str]:
55
+ """
56
+ The version spec of the package (e.g. `1.2.3`, `>=1.2.3`, `1.2.*`)
57
+ """
58
+ return self._nameless_match_spec.version
59
+
60
+ @property
61
+ def build(self) -> Optional[str]:
62
+ """
63
+ The build string of the package (e.g. `py37_0`, `py37h6de7cb9_0`, `py*`)
64
+ """
65
+ return self._nameless_match_spec.build
66
+
67
+ @property
68
+ def build_number(self) -> Optional[str]:
69
+ """
70
+ The build number of the package.
71
+ """
72
+ return self._nameless_match_spec.build_number
73
+
74
+ @property
75
+ def file_name(self) -> Optional[str]:
76
+ """
77
+ Match the specific filename of the package.
78
+ """
79
+ return self._nameless_match_spec.file_name
80
+
81
+ @property
82
+ def channel(self) -> Optional[Channel]:
83
+ """
84
+ The channel of the package.
85
+ """
86
+ channel = self._nameless_match_spec.channel
87
+ return channel and Channel._from_py_channel(channel)
88
+
89
+ @property
90
+ def subdir(self) -> Optional[str]:
91
+ """
92
+ The subdir of the channel.
93
+ """
94
+ return self._nameless_match_spec.subdir
95
+
96
+ @property
97
+ def namespace(self) -> Optional[str]:
98
+ """
99
+ The namespace of the package.
100
+ """
101
+ return self._nameless_match_spec.namespace
102
+
103
+ @property
104
+ def md5(self) -> Optional[bytes]:
105
+ """
106
+ The md5 hash of the package.
107
+ """
108
+ return self._nameless_match_spec.md5
109
+
110
+ @property
111
+ def sha256(self) -> Optional[bytes]:
112
+ """
113
+ The sha256 hash of the package.
114
+ """
115
+ return self._nameless_match_spec.sha256
116
+
117
+ @property
118
+ def extras(self) -> Optional[list[str]]:
119
+ """The extras (optional dependencies) of the package."""
120
+ return self._nameless_match_spec.extras
121
+
122
+ @property
123
+ def condition(self) -> Optional[str]:
124
+ """The condition under which this match spec applies."""
125
+ return self._nameless_match_spec.condition
126
+
127
+ def matches(self, package_record: PackageRecord) -> bool:
128
+ """
129
+ Match a MatchSpec against a PackageRecord
130
+ """
131
+ return self._nameless_match_spec.matches(package_record._record)
132
+
133
+ @classmethod
134
+ def _from_py_nameless_match_spec(cls, py_nameless_match_spec: PyNamelessMatchSpec) -> NamelessMatchSpec:
135
+ """
136
+ Construct py-rattler NamelessMatchSpec from PyNamelessMatchSpec FFI object.
137
+ """
138
+ nameless_match_spec = cls.__new__(cls)
139
+ nameless_match_spec._nameless_match_spec = py_nameless_match_spec
140
+
141
+ return nameless_match_spec
142
+
143
+ @classmethod
144
+ def from_match_spec(cls, spec: MatchSpec) -> NamelessMatchSpec:
145
+ """
146
+ Constructs a NamelessMatchSpec from a MatchSpec.
147
+
148
+ Examples
149
+ --------
150
+ ```python
151
+ >>> from rattler import MatchSpec
152
+ >>> NamelessMatchSpec.from_match_spec(MatchSpec("foo ==3.4"))
153
+ NamelessMatchSpec("==3.4")
154
+ >>>
155
+ ```
156
+ """
157
+ return cls._from_py_nameless_match_spec(PyNamelessMatchSpec.from_match_spec(spec._match_spec))
158
+
159
+ def __str__(self) -> str:
160
+ """
161
+ Returns a string representation of the NamelessMatchSpec.
162
+
163
+ Examples
164
+ --------
165
+ ```python
166
+ >>> str(NamelessMatchSpec("3.4"))
167
+ '==3.4'
168
+ >>>
169
+ ```
170
+ """
171
+ return self._nameless_match_spec.as_str()
172
+
173
+ def __repr__(self) -> str:
174
+ """
175
+ Returns a representation of the NamelessMatchSpec.
176
+
177
+ Examples
178
+ --------
179
+ ```python
180
+ >>> NamelessMatchSpec("3.4")
181
+ NamelessMatchSpec("==3.4")
182
+ >>>
183
+ ```
184
+ """
185
+ return f'NamelessMatchSpec("{self._nameless_match_spec.as_str()}")'
@@ -0,0 +1,21 @@
1
+ from rattler.networking.client import Client
2
+ from rattler.networking.fetch_repo_data import fetch_repo_data, CacheAction, FetchRepoDataOptions
3
+ from rattler.networking.middleware import (
4
+ AddHeadersMiddleware,
5
+ AuthenticationMiddleware,
6
+ GCSMiddleware,
7
+ MirrorMiddleware,
8
+ S3Middleware,
9
+ )
10
+
11
+ __all__ = [
12
+ "fetch_repo_data",
13
+ "FetchRepoDataOptions",
14
+ "CacheAction",
15
+ "Client",
16
+ "AddHeadersMiddleware",
17
+ "MirrorMiddleware",
18
+ "AuthenticationMiddleware",
19
+ "S3Middleware",
20
+ "GCSMiddleware",
21
+ ]
@@ -0,0 +1,74 @@
1
+ from __future__ import annotations
2
+
3
+ from rattler.networking.middleware import (
4
+ AddHeadersMiddleware,
5
+ AuthenticationMiddleware,
6
+ GCSMiddleware,
7
+ MirrorMiddleware,
8
+ OciMiddleware,
9
+ S3Middleware,
10
+ )
11
+ from rattler.rattler import PyClientWithMiddleware
12
+
13
+
14
+ class Client:
15
+ """
16
+ A client that can be used to make requests.
17
+ """
18
+
19
+ def __init__(
20
+ self,
21
+ middlewares: (
22
+ list[
23
+ AddHeadersMiddleware
24
+ | AuthenticationMiddleware
25
+ | MirrorMiddleware
26
+ | OciMiddleware
27
+ | GCSMiddleware
28
+ | S3Middleware
29
+ ]
30
+ | None
31
+ ) = None,
32
+ headers: dict[str, str] | None = None,
33
+ ) -> None:
34
+ self._client = PyClientWithMiddleware(
35
+ [middleware._middleware for middleware in middlewares] if middlewares else None, headers
36
+ )
37
+
38
+ @classmethod
39
+ def _from_ffi_object(cls, client: PyClientWithMiddleware) -> Client:
40
+ """
41
+ Construct py-rattler Client from PyClientWithMiddleware FFI object.
42
+ """
43
+ client = cls.__new__(cls)
44
+ client._client = client
45
+ return client
46
+
47
+ def __repr__(self) -> str:
48
+ """
49
+ Returns a representation of the Client
50
+
51
+ Examples
52
+ --------
53
+ ```python
54
+ >>> Client()
55
+ Client()
56
+ >>>
57
+ ```
58
+ """
59
+ return f"{type(self).__name__}()"
60
+
61
+ @staticmethod
62
+ def authenticated_client() -> Client:
63
+ """
64
+ Returns an authenticated client.
65
+
66
+ Examples
67
+ --------
68
+ ```python
69
+ >>> Client.authenticated_client()
70
+ Client()
71
+ >>>
72
+ ```
73
+ """
74
+ return Client([AuthenticationMiddleware()])
@@ -0,0 +1,103 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass
3
+ from typing import Callable, List, Literal, Optional, Union, TYPE_CHECKING
4
+
5
+ from rattler.networking.client import Client
6
+ from rattler.rattler import py_fetch_repo_data, PyFetchRepoDataOptions
7
+ from rattler.repo_data.sparse import SparseRepoData
8
+
9
+ if TYPE_CHECKING:
10
+ import os
11
+ from rattler.channel import Channel
12
+ from rattler.platform import Platform
13
+
14
+
15
+ CacheAction = Literal["cache-or-fetch", "use-cache-only", "force-cache-only", "no-cache"]
16
+ Variant = Literal["after-patches", "from-packages", "current"]
17
+
18
+
19
+ @dataclass
20
+ class FetchRepoDataOptions:
21
+ cache_action: CacheAction = "cache-or-fetch"
22
+ """How to interact with the cache.
23
+
24
+ * `'cache-or-fetch'` (default): Use the cache if its up to date or fetch from the URL if there is no valid cached value.
25
+ * `'use-cache-only'`: Only use the cache, but error out if the cache is not up to date
26
+ * `'force-cache-only'`: Only use the cache, ignore whether or not it is up to date.
27
+ * `'no-cache'`: Do not use the cache even if there is an up to date entry
28
+ """
29
+
30
+ variant: Variant = "after-patches"
31
+ """Which type of repodata to download
32
+
33
+ * `'after-patches'` (default): Fetch the `repodata.json` file. This `repodata.json` has repodata patches applied.
34
+ * `'from-packages'` Fetch the `repodata_from_packages.json` file
35
+ * `'current'`: Fetch `current_repodata.json` file. This file contains only the latest version of each package.
36
+ """
37
+
38
+ jlap_enabled: bool = True
39
+ """Whether the JLAP compression is enabled or not."""
40
+
41
+ zstd_enabled: bool = True
42
+ """Whether the ZSTD compression is enabled or not."""
43
+
44
+ bz2_enabled: bool = True
45
+ """Whether the BZ2 compression is enabled or not."""
46
+
47
+ def _into_py(self) -> PyFetchRepoDataOptions:
48
+ """
49
+ Converts this object into a type that can be used by the Rust code.
50
+
51
+ Examples
52
+ --------
53
+ ```python
54
+ >>> FetchRepoDataOptions()._into_py() # doctest: +ELLIPSIS
55
+ <builtins.PyFetchRepoDataOptions object at 0x...>
56
+ >>>
57
+ ```
58
+ """
59
+ return PyFetchRepoDataOptions(
60
+ cache_action=self.cache_action,
61
+ variant=self.variant,
62
+ jlap_enabled=self.jlap_enabled,
63
+ zstd_enabled=self.zstd_enabled,
64
+ bz2_enabled=self.bz2_enabled,
65
+ )
66
+
67
+
68
+ async def fetch_repo_data(
69
+ *,
70
+ channels: List[Channel],
71
+ platforms: List[Platform],
72
+ cache_path: Union[str, os.PathLike[str]],
73
+ callback: Optional[Callable[[int, int], None]],
74
+ client: Optional[Client] = None,
75
+ fetch_options: Optional[FetchRepoDataOptions] = None,
76
+ ) -> List[SparseRepoData]:
77
+ """
78
+ Returns a list of RepoData for given channels and platform.
79
+
80
+ Arguments:
81
+ channels: A list of `Channel`s to fetch repo data.
82
+ platforms: A list of `Platform`s for which the repo data
83
+ should be fetched.
84
+ cache_path: A `os.PathLike[str]` where the repo data should
85
+ be downloaded.
86
+ callback: A `Callable[[int, int], None]` to report the download
87
+ progress of repo data.
88
+ client: A `Client` to use for fetching the repo data.
89
+
90
+ Returns:
91
+ A list of `SparseRepoData` for requested channels and platforms.
92
+ """
93
+ fetch_options = fetch_options or FetchRepoDataOptions()
94
+ repo_data_list = await py_fetch_repo_data(
95
+ [channel._channel for channel in channels],
96
+ [platform._inner for platform in platforms],
97
+ cache_path,
98
+ callback,
99
+ client._client if client else None,
100
+ fetch_options._into_py(),
101
+ )
102
+
103
+ return [SparseRepoData._from_py_sparse_repo_data(repo_data) for repo_data in repo_data_list]