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.
- py_rattler-0.22.0.dist-info/METADATA +208 -0
- py_rattler-0.22.0.dist-info/RECORD +68 -0
- py_rattler-0.22.0.dist-info/WHEEL +4 -0
- rattler/__init__.py +114 -0
- rattler/channel/__init__.py +5 -0
- rattler/channel/channel.py +94 -0
- rattler/channel/channel_config.py +43 -0
- rattler/channel/channel_priority.py +14 -0
- rattler/exceptions.py +120 -0
- rattler/explicit_environment/__init__.py +3 -0
- rattler/explicit_environment/environment.py +69 -0
- rattler/index/__init__.py +3 -0
- rattler/index/index.py +112 -0
- rattler/install/__init__.py +3 -0
- rattler/install/installer.py +96 -0
- rattler/lock/__init__.py +23 -0
- rattler/lock/channel.py +52 -0
- rattler/lock/environment.py +213 -0
- rattler/lock/hash.py +33 -0
- rattler/lock/lock_file.py +118 -0
- rattler/lock/package.py +302 -0
- rattler/match_spec/__init__.py +4 -0
- rattler/match_spec/match_spec.py +294 -0
- rattler/match_spec/nameless_match_spec.py +185 -0
- rattler/networking/__init__.py +21 -0
- rattler/networking/client.py +74 -0
- rattler/networking/fetch_repo_data.py +103 -0
- rattler/networking/middleware.py +234 -0
- rattler/package/__init__.py +26 -0
- rattler/package/about_json.py +329 -0
- rattler/package/index_json.py +437 -0
- rattler/package/no_arch_type.py +142 -0
- rattler/package/package_name.py +204 -0
- rattler/package/package_name_matcher.py +81 -0
- rattler/package/paths_json.py +696 -0
- rattler/package/run_exports_json.py +268 -0
- rattler/package_streaming/__init__.py +26 -0
- rattler/platform/__init__.py +4 -0
- rattler/platform/arch.py +59 -0
- rattler/platform/platform.py +217 -0
- rattler/prefix/__init__.py +4 -0
- rattler/prefix/prefix_paths.py +442 -0
- rattler/prefix/prefix_record.py +234 -0
- rattler/pty/__init__.py +25 -0
- rattler/pty/pty_process.py +391 -0
- rattler/pty/pty_session.py +241 -0
- rattler/py.typed +0 -0
- rattler/rattler.abi3.so +0 -0
- rattler/repo_data/__init__.py +19 -0
- rattler/repo_data/gateway.py +337 -0
- rattler/repo_data/package_record.py +938 -0
- rattler/repo_data/patch_instructions.py +22 -0
- rattler/repo_data/record.py +164 -0
- rattler/repo_data/repo_data.py +74 -0
- rattler/repo_data/source.py +85 -0
- rattler/repo_data/sparse.py +356 -0
- rattler/shell/__init__.py +3 -0
- rattler/shell/shell.py +134 -0
- rattler/solver/__init__.py +3 -0
- rattler/solver/solver.py +220 -0
- rattler/utils/rattler_version.py +19 -0
- rattler/version/__init__.py +5 -0
- rattler/version/version.py +591 -0
- rattler/version/version_spec.py +184 -0
- rattler/version/with_source.py +80 -0
- rattler/virtual_package/__init__.py +4 -0
- rattler/virtual_package/generic.py +136 -0
- rattler/virtual_package/virtual_package.py +201 -0
|
@@ -0,0 +1,938 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
from typing import List, Optional, TYPE_CHECKING
|
|
4
|
+
import datetime
|
|
5
|
+
|
|
6
|
+
from rattler import VersionWithSource
|
|
7
|
+
from rattler.match_spec.match_spec import MatchSpec
|
|
8
|
+
from rattler.package.no_arch_type import NoArchType, NoArchLiteral
|
|
9
|
+
from rattler.package.package_name import PackageName
|
|
10
|
+
from rattler.platform.platform import Platform
|
|
11
|
+
from rattler.rattler import PyRecord, ParsePlatformError
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
import networkx as nx
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PackageRecord:
|
|
18
|
+
"""
|
|
19
|
+
A single record in the Conda repodata. A single
|
|
20
|
+
record refers to a single binary distribution
|
|
21
|
+
of a package on a Conda channel.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
_record: PyRecord
|
|
25
|
+
|
|
26
|
+
def matches(self, spec: MatchSpec) -> bool:
|
|
27
|
+
"""
|
|
28
|
+
Match a [`PackageRecord`] against a [`MatchSpec`].
|
|
29
|
+
|
|
30
|
+
Examples
|
|
31
|
+
--------
|
|
32
|
+
```python
|
|
33
|
+
>>> from rattler import MatchSpec
|
|
34
|
+
>>> record = PackageRecord.from_index_json(
|
|
35
|
+
... "../test-data/conda-meta/pysocks-1.7.1-pyh0701188_6.json"
|
|
36
|
+
... )
|
|
37
|
+
>>> spec = MatchSpec("pysocks")
|
|
38
|
+
>>> record.matches(spec)
|
|
39
|
+
True
|
|
40
|
+
>>> spec = MatchSpec("pysocks>=1.7")
|
|
41
|
+
>>> record.matches(spec)
|
|
42
|
+
True
|
|
43
|
+
>>> spec = MatchSpec("pysocks<1.7")
|
|
44
|
+
>>> record.matches(spec)
|
|
45
|
+
False
|
|
46
|
+
>>>
|
|
47
|
+
```
|
|
48
|
+
"""
|
|
49
|
+
return spec.matches(self)
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def from_index_json(
|
|
53
|
+
path: os.PathLike[str],
|
|
54
|
+
size: Optional[int] = None,
|
|
55
|
+
sha256: Optional[str] = None,
|
|
56
|
+
md5: Optional[str] = None,
|
|
57
|
+
) -> PackageRecord:
|
|
58
|
+
"""
|
|
59
|
+
Builds a PackageRecord from an `index.json`.
|
|
60
|
+
These can be found in `info` directory inside an
|
|
61
|
+
extracted package archive.
|
|
62
|
+
|
|
63
|
+
Examples
|
|
64
|
+
--------
|
|
65
|
+
```python
|
|
66
|
+
>>> record = PackageRecord.from_index_json(
|
|
67
|
+
... "../test-data/conda-meta/pysocks-1.7.1-pyh0701188_6.json"
|
|
68
|
+
... )
|
|
69
|
+
>>> assert isinstance(record, PackageRecord)
|
|
70
|
+
>>> record.name
|
|
71
|
+
PackageName("pysocks")
|
|
72
|
+
>>> record.version
|
|
73
|
+
VersionWithSource(version="1.7.1", source="1.7.1")
|
|
74
|
+
>>> record.build
|
|
75
|
+
'pyh0701188_6'
|
|
76
|
+
>>>
|
|
77
|
+
```
|
|
78
|
+
"""
|
|
79
|
+
return PackageRecord._from_py_record(PyRecord.from_index_json(path, size, sha256, md5))
|
|
80
|
+
|
|
81
|
+
@staticmethod
|
|
82
|
+
def sort_topologically(records: List[PackageRecord]) -> List[PackageRecord]:
|
|
83
|
+
"""
|
|
84
|
+
Sorts the records topologically.
|
|
85
|
+
This function is deterministic, meaning that it will return the same result
|
|
86
|
+
regardless of the order of records and of the depends vector inside the records.
|
|
87
|
+
Note that this function only works for packages with unique names.
|
|
88
|
+
|
|
89
|
+
Examples
|
|
90
|
+
--------
|
|
91
|
+
```python
|
|
92
|
+
>>> from os import listdir
|
|
93
|
+
>>> from os.path import isfile, join
|
|
94
|
+
>>> from rattler import PrefixRecord
|
|
95
|
+
>>> records = [
|
|
96
|
+
... PrefixRecord.from_path(join("../test-data/conda-meta/", f))
|
|
97
|
+
... for f in listdir("../test-data/conda-meta")
|
|
98
|
+
... if isfile(join("../test-data/conda-meta", f))
|
|
99
|
+
... ]
|
|
100
|
+
>>> sorted = PackageRecord.sort_topologically(records)
|
|
101
|
+
>>> sorted[0].name
|
|
102
|
+
PackageName("python_abi")
|
|
103
|
+
>>> # Verify it's deterministic by sorting again
|
|
104
|
+
>>> sorted2 = PackageRecord.sort_topologically(records)
|
|
105
|
+
>>> [str(r) for r in sorted] == [str(r) for r in sorted2]
|
|
106
|
+
True
|
|
107
|
+
>>>
|
|
108
|
+
```
|
|
109
|
+
"""
|
|
110
|
+
return [PackageRecord._from_py_record(p) for p in PyRecord.sort_topologically(records)]
|
|
111
|
+
|
|
112
|
+
@staticmethod
|
|
113
|
+
def to_graph(records: List[PackageRecord]) -> nx.DiGraph: # type: ignore[type-arg]
|
|
114
|
+
"""
|
|
115
|
+
Converts a list of PackageRecords to a DAG (`networkx.DiGraph`).
|
|
116
|
+
The nodes in the graph are the PackageRecords and the edges are the dependencies.
|
|
117
|
+
|
|
118
|
+
Note: Virtual packages (starting with `__`) are skipped.
|
|
119
|
+
"""
|
|
120
|
+
try:
|
|
121
|
+
import networkx as nx
|
|
122
|
+
except ImportError:
|
|
123
|
+
raise ImportError("networkx is not installed") from None
|
|
124
|
+
|
|
125
|
+
names_to_records = {record.name: record for record in records}
|
|
126
|
+
|
|
127
|
+
graph = nx.DiGraph() # type: ignore[var-annotated]
|
|
128
|
+
for record in records:
|
|
129
|
+
graph.add_node(record)
|
|
130
|
+
for dep in record.depends:
|
|
131
|
+
name = dep.split(" ")[0]
|
|
132
|
+
if name.startswith("__"):
|
|
133
|
+
# this is a virtual package, so we just skip it
|
|
134
|
+
continue
|
|
135
|
+
graph.add_edge(record, names_to_records[PackageName(name)])
|
|
136
|
+
|
|
137
|
+
return graph
|
|
138
|
+
|
|
139
|
+
@staticmethod
|
|
140
|
+
def validate(records: List[PackageRecord]) -> None:
|
|
141
|
+
"""
|
|
142
|
+
Validate that the given package records are valid w.r.t. 'depends' and 'constrains'.
|
|
143
|
+
|
|
144
|
+
This function will return nothing if all records form a valid environment, i.e., all dependencies
|
|
145
|
+
of each package are satisfied by the other packages in the list.
|
|
146
|
+
If there is a dependency that is not satisfied, this function will raise an exception.
|
|
147
|
+
|
|
148
|
+
Examples
|
|
149
|
+
--------
|
|
150
|
+
```python
|
|
151
|
+
>>> from os import listdir
|
|
152
|
+
>>> from os.path import isfile, join
|
|
153
|
+
>>> from rattler import PrefixRecord
|
|
154
|
+
>>> from rattler.exceptions import ValidatePackageRecordsException
|
|
155
|
+
>>> records = [
|
|
156
|
+
... PrefixRecord.from_path(join("../test-data/conda-meta/", f))
|
|
157
|
+
... for f in sorted(listdir("../test-data/conda-meta"))
|
|
158
|
+
... if isfile(join("../test-data/conda-meta", f))
|
|
159
|
+
... ]
|
|
160
|
+
>>> try:
|
|
161
|
+
... PackageRecord.validate(records)
|
|
162
|
+
... except ValidatePackageRecordsException as e:
|
|
163
|
+
... print(e)
|
|
164
|
+
package 'libsqlite=3.40.0=hcfcfb64_0' has dependency 'ucrt >=10.0.20348.0', which is not in the environment
|
|
165
|
+
>>>
|
|
166
|
+
```
|
|
167
|
+
"""
|
|
168
|
+
return PyRecord.validate(records)
|
|
169
|
+
|
|
170
|
+
@classmethod
|
|
171
|
+
def _from_py_record(cls, py_record: PyRecord) -> PackageRecord:
|
|
172
|
+
"""
|
|
173
|
+
Construct Rattler PackageRecord from FFI PyRecord object.
|
|
174
|
+
"""
|
|
175
|
+
|
|
176
|
+
# quick sanity check
|
|
177
|
+
assert py_record.is_package_record
|
|
178
|
+
record = cls.__new__(cls)
|
|
179
|
+
record._record = py_record
|
|
180
|
+
return record
|
|
181
|
+
|
|
182
|
+
def __init__(
|
|
183
|
+
self,
|
|
184
|
+
name: str | PackageName,
|
|
185
|
+
version: str | VersionWithSource,
|
|
186
|
+
build: str,
|
|
187
|
+
build_number: int,
|
|
188
|
+
subdir: str | Platform,
|
|
189
|
+
arch: Optional[str] = None,
|
|
190
|
+
platform: Optional[str] = None,
|
|
191
|
+
noarch: Optional[NoArchType | NoArchLiteral] = None,
|
|
192
|
+
depends: Optional[List[str]] = None,
|
|
193
|
+
constrains: Optional[List[str]] = None,
|
|
194
|
+
sha256: Optional[bytes] = None,
|
|
195
|
+
md5: Optional[bytes] = None,
|
|
196
|
+
size: Optional[int] = None,
|
|
197
|
+
features: Optional[List[str]] = None,
|
|
198
|
+
legacy_bz2_md5: Optional[bytes] = None,
|
|
199
|
+
legacy_bz2_size: Optional[int] = None,
|
|
200
|
+
license: Optional[str] = None,
|
|
201
|
+
license_family: Optional[str] = None,
|
|
202
|
+
python_site_packages_path: Optional[str] = None,
|
|
203
|
+
) -> None:
|
|
204
|
+
if isinstance(subdir, str):
|
|
205
|
+
try:
|
|
206
|
+
subdir = Platform(subdir)
|
|
207
|
+
except ParsePlatformError:
|
|
208
|
+
# if the string is not a valid platform, we just keep it as a string
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
if isinstance(subdir, Platform):
|
|
212
|
+
if arch is None:
|
|
213
|
+
subdir_arch = subdir.arch
|
|
214
|
+
arch = str(subdir_arch) if subdir_arch is not None else arch
|
|
215
|
+
platform = subdir.only_platform if platform is None else platform
|
|
216
|
+
|
|
217
|
+
# convert str to PackageName
|
|
218
|
+
if isinstance(name, str):
|
|
219
|
+
name = PackageName(name)
|
|
220
|
+
|
|
221
|
+
# convert str to VersionWithSource
|
|
222
|
+
if isinstance(version, str):
|
|
223
|
+
version = VersionWithSource(version)
|
|
224
|
+
|
|
225
|
+
if not isinstance(noarch, NoArchType):
|
|
226
|
+
noarch = NoArchType(noarch)
|
|
227
|
+
|
|
228
|
+
self._record = PyRecord.create(
|
|
229
|
+
name._name,
|
|
230
|
+
(version._version, version._source),
|
|
231
|
+
build,
|
|
232
|
+
build_number,
|
|
233
|
+
str(subdir),
|
|
234
|
+
str(arch) if arch is not None else None,
|
|
235
|
+
platform,
|
|
236
|
+
noarch._noarch,
|
|
237
|
+
python_site_packages_path,
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
if constrains is not None:
|
|
241
|
+
self._record.constrains = constrains
|
|
242
|
+
if depends is not None:
|
|
243
|
+
self._record.depends = depends
|
|
244
|
+
if sha256 is not None:
|
|
245
|
+
self._record.sha256 = sha256
|
|
246
|
+
if md5 is not None:
|
|
247
|
+
self._record.md5 = md5
|
|
248
|
+
if size is not None:
|
|
249
|
+
self._record.size = size
|
|
250
|
+
if features is not None:
|
|
251
|
+
self._record.features = features
|
|
252
|
+
if legacy_bz2_md5 is not None:
|
|
253
|
+
self._record.legacy_bz2_md5 = legacy_bz2_md5
|
|
254
|
+
if legacy_bz2_size is not None:
|
|
255
|
+
self._record.legacy_bz2_size = legacy_bz2_size
|
|
256
|
+
if license is not None:
|
|
257
|
+
self._record.license = license
|
|
258
|
+
if license_family is not None:
|
|
259
|
+
self._record.license_family = license_family
|
|
260
|
+
|
|
261
|
+
@property
|
|
262
|
+
def arch(self) -> Optional[str]:
|
|
263
|
+
"""
|
|
264
|
+
Optionally the architecture the package supports.
|
|
265
|
+
|
|
266
|
+
Examples
|
|
267
|
+
--------
|
|
268
|
+
```python
|
|
269
|
+
>>> from rattler import PrefixRecord
|
|
270
|
+
>>> record = PrefixRecord.from_path(
|
|
271
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
272
|
+
... )
|
|
273
|
+
>>> record.arch
|
|
274
|
+
'x86_64'
|
|
275
|
+
>>> record.arch = "arm64"
|
|
276
|
+
>>> record.arch
|
|
277
|
+
'arm64'
|
|
278
|
+
>>> record.arch = None
|
|
279
|
+
>>> record.arch is None
|
|
280
|
+
True
|
|
281
|
+
>>>
|
|
282
|
+
```
|
|
283
|
+
"""
|
|
284
|
+
return self._record.arch
|
|
285
|
+
|
|
286
|
+
@arch.setter
|
|
287
|
+
def arch(self, value: Optional[str]) -> None:
|
|
288
|
+
self._record.arch = value
|
|
289
|
+
|
|
290
|
+
@property
|
|
291
|
+
def build(self) -> str:
|
|
292
|
+
"""
|
|
293
|
+
The build string of the package.
|
|
294
|
+
|
|
295
|
+
Examples
|
|
296
|
+
--------
|
|
297
|
+
```python
|
|
298
|
+
>>> from rattler import PrefixRecord
|
|
299
|
+
>>> record = PrefixRecord.from_path(
|
|
300
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
301
|
+
... )
|
|
302
|
+
>>> record.build
|
|
303
|
+
'hcfcfb64_0'
|
|
304
|
+
>>> record.build = "new_build_1"
|
|
305
|
+
>>> record.build
|
|
306
|
+
'new_build_1'
|
|
307
|
+
>>>
|
|
308
|
+
```
|
|
309
|
+
"""
|
|
310
|
+
return self._record.build
|
|
311
|
+
|
|
312
|
+
@build.setter
|
|
313
|
+
def build(self, value: str) -> None:
|
|
314
|
+
self._record.build = value
|
|
315
|
+
|
|
316
|
+
@property
|
|
317
|
+
def build_number(self) -> int:
|
|
318
|
+
"""
|
|
319
|
+
The build number of the package.
|
|
320
|
+
|
|
321
|
+
Examples
|
|
322
|
+
--------
|
|
323
|
+
```python
|
|
324
|
+
>>> from rattler import PrefixRecord
|
|
325
|
+
>>> record = PrefixRecord.from_path(
|
|
326
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
327
|
+
... )
|
|
328
|
+
>>> record.build_number
|
|
329
|
+
0
|
|
330
|
+
>>> record.build_number = 42
|
|
331
|
+
>>> record.build_number
|
|
332
|
+
42
|
|
333
|
+
>>>
|
|
334
|
+
```
|
|
335
|
+
"""
|
|
336
|
+
return self._record.build_number
|
|
337
|
+
|
|
338
|
+
@build_number.setter
|
|
339
|
+
def build_number(self, value: int) -> None:
|
|
340
|
+
self._record.build_number = value
|
|
341
|
+
|
|
342
|
+
@property
|
|
343
|
+
def constrains(self) -> List[str]:
|
|
344
|
+
"""
|
|
345
|
+
Additional constraints on packages.
|
|
346
|
+
Constrains are different from depends in that packages
|
|
347
|
+
specified in depends must be installed next to this package,
|
|
348
|
+
whereas packages specified in constrains are not required to
|
|
349
|
+
be installed, but if they are installed they must follow
|
|
350
|
+
these constraints.
|
|
351
|
+
|
|
352
|
+
Examples
|
|
353
|
+
--------
|
|
354
|
+
```python
|
|
355
|
+
>>> from rattler import PrefixRecord
|
|
356
|
+
>>> record = PrefixRecord.from_path(
|
|
357
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
358
|
+
... )
|
|
359
|
+
>>> record.constrains
|
|
360
|
+
[]
|
|
361
|
+
>>> record.constrains = ["python >=3.6"]
|
|
362
|
+
>>> record.constrains
|
|
363
|
+
['python >=3.6']
|
|
364
|
+
>>>
|
|
365
|
+
```
|
|
366
|
+
"""
|
|
367
|
+
return self._record.constrains
|
|
368
|
+
|
|
369
|
+
@constrains.setter
|
|
370
|
+
def constrains(self, value: List[str]) -> None:
|
|
371
|
+
self._record.constrains = value
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def depends(self) -> List[str]:
|
|
375
|
+
"""
|
|
376
|
+
Specification of packages this package depends on.
|
|
377
|
+
|
|
378
|
+
Examples
|
|
379
|
+
--------
|
|
380
|
+
```python
|
|
381
|
+
>>> from rattler import PrefixRecord
|
|
382
|
+
>>> record = PrefixRecord.from_path(
|
|
383
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
384
|
+
... )
|
|
385
|
+
>>> record.depends
|
|
386
|
+
['ucrt >=10.0.20348.0', 'vc >=14.2,<15', 'vs2015_runtime >=14.29.30139']
|
|
387
|
+
>>> record.depends = ["python >=3.6"]
|
|
388
|
+
>>> record.depends
|
|
389
|
+
['python >=3.6']
|
|
390
|
+
>>>
|
|
391
|
+
```
|
|
392
|
+
"""
|
|
393
|
+
return self._record.depends
|
|
394
|
+
|
|
395
|
+
@depends.setter
|
|
396
|
+
def depends(self, value: List[str]) -> None:
|
|
397
|
+
self._record.depends = value
|
|
398
|
+
|
|
399
|
+
@property
|
|
400
|
+
def features(self) -> Optional[str]:
|
|
401
|
+
"""
|
|
402
|
+
Features are a deprecated way to specify different feature
|
|
403
|
+
sets for the conda solver. This is not supported anymore and
|
|
404
|
+
should not be used. Instead, mutex packages should be used
|
|
405
|
+
to specify mutually exclusive features.
|
|
406
|
+
|
|
407
|
+
Examples
|
|
408
|
+
--------
|
|
409
|
+
```python
|
|
410
|
+
>>> record = PackageRecord.from_index_json(
|
|
411
|
+
... "../test-data/conda-meta/pysocks-1.7.1-pyh0701188_6.json"
|
|
412
|
+
... )
|
|
413
|
+
>>> record.features is None
|
|
414
|
+
True
|
|
415
|
+
>>> record.features = "feature1"
|
|
416
|
+
>>> record.features
|
|
417
|
+
'feature1'
|
|
418
|
+
>>> record.features = None
|
|
419
|
+
>>> record.features is None
|
|
420
|
+
True
|
|
421
|
+
>>>
|
|
422
|
+
```
|
|
423
|
+
"""
|
|
424
|
+
return self._record.features
|
|
425
|
+
|
|
426
|
+
@features.setter
|
|
427
|
+
def features(self, value: Optional[str]) -> None:
|
|
428
|
+
self._record.features = value
|
|
429
|
+
|
|
430
|
+
@property
|
|
431
|
+
def legacy_bz2_md5(self) -> Optional[bytes]:
|
|
432
|
+
"""
|
|
433
|
+
A deprecated md5 hash.
|
|
434
|
+
|
|
435
|
+
Examples
|
|
436
|
+
--------
|
|
437
|
+
```python
|
|
438
|
+
>>> record = PackageRecord.from_index_json(
|
|
439
|
+
... "../test-data/conda-meta/pysocks-1.7.1-pyh0701188_6.json"
|
|
440
|
+
... )
|
|
441
|
+
>>> record.legacy_bz2_md5 is None
|
|
442
|
+
True
|
|
443
|
+
>>> record.legacy_bz2_md5 = bytes.fromhex("2ddbbaf3a82b46ac7214681262e3d746")
|
|
444
|
+
>>> record.legacy_bz2_md5.hex()
|
|
445
|
+
'2ddbbaf3a82b46ac7214681262e3d746'
|
|
446
|
+
>>> record.legacy_bz2_md5 = None
|
|
447
|
+
>>> record.legacy_bz2_md5 is None
|
|
448
|
+
True
|
|
449
|
+
>>>
|
|
450
|
+
```
|
|
451
|
+
"""
|
|
452
|
+
return self._record.legacy_bz2_md5
|
|
453
|
+
|
|
454
|
+
@legacy_bz2_md5.setter
|
|
455
|
+
def legacy_bz2_md5(self, value: Optional[bytes]) -> None:
|
|
456
|
+
self._record.legacy_bz2_md5 = value
|
|
457
|
+
|
|
458
|
+
@property
|
|
459
|
+
def legacy_bz2_size(self) -> Optional[int]:
|
|
460
|
+
"""
|
|
461
|
+
A deprecated package archive size.
|
|
462
|
+
|
|
463
|
+
Examples
|
|
464
|
+
--------
|
|
465
|
+
```python
|
|
466
|
+
>>> record = PackageRecord.from_index_json(
|
|
467
|
+
... "../test-data/conda-meta/pysocks-1.7.1-pyh0701188_6.json"
|
|
468
|
+
... )
|
|
469
|
+
>>> record.legacy_bz2_size is None
|
|
470
|
+
True
|
|
471
|
+
>>> record.legacy_bz2_size = 42
|
|
472
|
+
>>> record.legacy_bz2_size
|
|
473
|
+
42
|
|
474
|
+
>>> record.legacy_bz2_size = None
|
|
475
|
+
>>> record.legacy_bz2_size is None
|
|
476
|
+
True
|
|
477
|
+
>>>
|
|
478
|
+
```
|
|
479
|
+
"""
|
|
480
|
+
return self._record.legacy_bz2_size
|
|
481
|
+
|
|
482
|
+
@legacy_bz2_size.setter
|
|
483
|
+
def legacy_bz2_size(self, value: Optional[int]) -> None:
|
|
484
|
+
self._record.legacy_bz2_size = value
|
|
485
|
+
|
|
486
|
+
@property
|
|
487
|
+
def license(self) -> Optional[str]:
|
|
488
|
+
"""
|
|
489
|
+
The specific license of the package.
|
|
490
|
+
|
|
491
|
+
Examples
|
|
492
|
+
--------
|
|
493
|
+
```python
|
|
494
|
+
>>> from rattler import PrefixRecord
|
|
495
|
+
>>> record = PrefixRecord.from_path(
|
|
496
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
497
|
+
... )
|
|
498
|
+
>>> record.license
|
|
499
|
+
'Unlicense'
|
|
500
|
+
>>> record.license = "MIT"
|
|
501
|
+
>>> record.license
|
|
502
|
+
'MIT'
|
|
503
|
+
>>> record.license = None
|
|
504
|
+
>>> record.license is None
|
|
505
|
+
True
|
|
506
|
+
>>>
|
|
507
|
+
```
|
|
508
|
+
"""
|
|
509
|
+
return self._record.license
|
|
510
|
+
|
|
511
|
+
@license.setter
|
|
512
|
+
def license(self, value: Optional[str]) -> None:
|
|
513
|
+
self._record.license = value
|
|
514
|
+
|
|
515
|
+
@property
|
|
516
|
+
def license_family(self) -> Optional[str]:
|
|
517
|
+
"""
|
|
518
|
+
The license family.
|
|
519
|
+
|
|
520
|
+
Examples
|
|
521
|
+
--------
|
|
522
|
+
```python
|
|
523
|
+
>>> from rattler import PrefixRecord
|
|
524
|
+
>>> record = PrefixRecord.from_path(
|
|
525
|
+
... "../test-data/conda-meta/pip-23.0-pyhd8ed1ab_0.json"
|
|
526
|
+
... )
|
|
527
|
+
>>> record.license_family
|
|
528
|
+
'MIT'
|
|
529
|
+
>>> record.license_family = "BSD"
|
|
530
|
+
>>> record.license_family
|
|
531
|
+
'BSD'
|
|
532
|
+
>>> record.license_family = None
|
|
533
|
+
>>> record.license_family is None
|
|
534
|
+
True
|
|
535
|
+
>>>
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
"""
|
|
539
|
+
return self._record.license_family
|
|
540
|
+
|
|
541
|
+
@license_family.setter
|
|
542
|
+
def license_family(self, value: Optional[str]) -> None:
|
|
543
|
+
self._record.license_family = value
|
|
544
|
+
|
|
545
|
+
@property
|
|
546
|
+
def md5(self) -> Optional[bytes]:
|
|
547
|
+
"""
|
|
548
|
+
Optionally a MD5 hash of the package archive.
|
|
549
|
+
|
|
550
|
+
Examples
|
|
551
|
+
--------
|
|
552
|
+
```python
|
|
553
|
+
>>> from rattler import PrefixRecord
|
|
554
|
+
>>> record = PrefixRecord.from_path(
|
|
555
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
556
|
+
... )
|
|
557
|
+
>>> record.md5.hex()
|
|
558
|
+
'5e5a97795de72f8cc3baf3d9ea6327a2'
|
|
559
|
+
>>> record.md5 = bytes.fromhex("2ddbbaf3a82b46ac7214681262e3d746")
|
|
560
|
+
>>> record.md5.hex()
|
|
561
|
+
'2ddbbaf3a82b46ac7214681262e3d746'
|
|
562
|
+
>>> record.md5 = None
|
|
563
|
+
>>> record.md5 is None
|
|
564
|
+
True
|
|
565
|
+
>>>
|
|
566
|
+
```
|
|
567
|
+
"""
|
|
568
|
+
return self._record.md5
|
|
569
|
+
|
|
570
|
+
@md5.setter
|
|
571
|
+
def md5(self, value: Optional[bytes]) -> None:
|
|
572
|
+
self._record.md5 = value
|
|
573
|
+
|
|
574
|
+
@property
|
|
575
|
+
def name(self) -> PackageName:
|
|
576
|
+
"""
|
|
577
|
+
The name of the package.
|
|
578
|
+
|
|
579
|
+
Examples
|
|
580
|
+
--------
|
|
581
|
+
```python
|
|
582
|
+
>>> from rattler import PrefixRecord, PackageName
|
|
583
|
+
>>> record = PrefixRecord.from_path(
|
|
584
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
585
|
+
... )
|
|
586
|
+
>>> record.name
|
|
587
|
+
PackageName("libsqlite")
|
|
588
|
+
>>> record.name = PackageName("newname")
|
|
589
|
+
>>> record.name
|
|
590
|
+
PackageName("newname")
|
|
591
|
+
>>>
|
|
592
|
+
```
|
|
593
|
+
"""
|
|
594
|
+
return PackageName._from_py_package_name(self._record.name)
|
|
595
|
+
|
|
596
|
+
@name.setter
|
|
597
|
+
def name(self, value: PackageName) -> None:
|
|
598
|
+
self._record.name = value._name
|
|
599
|
+
|
|
600
|
+
@property
|
|
601
|
+
def noarch(self) -> NoArchType:
|
|
602
|
+
"""
|
|
603
|
+
The noarch type of the package.
|
|
604
|
+
|
|
605
|
+
Examples
|
|
606
|
+
--------
|
|
607
|
+
```python
|
|
608
|
+
>>> from rattler import PrefixRecord
|
|
609
|
+
>>> record = PrefixRecord.from_path(
|
|
610
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
611
|
+
... )
|
|
612
|
+
>>> record.noarch
|
|
613
|
+
NoArchType(None)
|
|
614
|
+
>>> record = PrefixRecord.from_path(
|
|
615
|
+
... "../test-data/conda-meta/pip-23.0-pyhd8ed1ab_0.json"
|
|
616
|
+
... )
|
|
617
|
+
>>> record.noarch
|
|
618
|
+
NoArchType("python")
|
|
619
|
+
>>> record.noarch = NoArchType("generic")
|
|
620
|
+
>>> record.noarch
|
|
621
|
+
NoArchType("generic")
|
|
622
|
+
>>> record.noarch = NoArchType(None)
|
|
623
|
+
>>> record.noarch.none
|
|
624
|
+
True
|
|
625
|
+
>>>
|
|
626
|
+
```
|
|
627
|
+
"""
|
|
628
|
+
return NoArchType._from_py_no_arch_type(self._record.noarch)
|
|
629
|
+
|
|
630
|
+
@noarch.setter
|
|
631
|
+
def noarch(self, value: NoArchType) -> None:
|
|
632
|
+
self._record.noarch = value._noarch
|
|
633
|
+
|
|
634
|
+
@property
|
|
635
|
+
def platform(self) -> Optional[str]:
|
|
636
|
+
"""
|
|
637
|
+
Optionally the platform the package supports.
|
|
638
|
+
|
|
639
|
+
Examples
|
|
640
|
+
--------
|
|
641
|
+
```python
|
|
642
|
+
>>> from rattler import PrefixRecord
|
|
643
|
+
>>> record = PrefixRecord.from_path(
|
|
644
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
645
|
+
... )
|
|
646
|
+
>>> record.platform
|
|
647
|
+
'win32'
|
|
648
|
+
>>> record.platform = "linux"
|
|
649
|
+
>>> record.platform
|
|
650
|
+
'linux'
|
|
651
|
+
>>> record.platform = None
|
|
652
|
+
>>> record.platform is None
|
|
653
|
+
True
|
|
654
|
+
>>>
|
|
655
|
+
```
|
|
656
|
+
"""
|
|
657
|
+
return self._record.platform
|
|
658
|
+
|
|
659
|
+
@platform.setter
|
|
660
|
+
def platform(self, value: Optional[str]) -> None:
|
|
661
|
+
self._record.platform = value
|
|
662
|
+
|
|
663
|
+
@property
|
|
664
|
+
def sha256(self) -> Optional[bytes]:
|
|
665
|
+
"""
|
|
666
|
+
Optionally a SHA256 hash of the package archive.
|
|
667
|
+
|
|
668
|
+
Examples
|
|
669
|
+
--------
|
|
670
|
+
```python
|
|
671
|
+
>>> from rattler import PrefixRecord
|
|
672
|
+
>>> record = PrefixRecord.from_path(
|
|
673
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
674
|
+
... )
|
|
675
|
+
>>> record.sha256.hex()
|
|
676
|
+
'4e50b3d90a351c9d47d239d3f90fce4870df2526e4f7fef35203ab3276a6dfc9'
|
|
677
|
+
>>> record.sha256 = bytes.fromhex("edd7dd24fc070fad8ca690a920d94b6312a376faa96b47c657f9ef5fe5a97dd1")
|
|
678
|
+
>>> record.sha256.hex()
|
|
679
|
+
'edd7dd24fc070fad8ca690a920d94b6312a376faa96b47c657f9ef5fe5a97dd1'
|
|
680
|
+
>>> record.sha256 = None
|
|
681
|
+
>>> record.sha256 is None
|
|
682
|
+
True
|
|
683
|
+
>>>
|
|
684
|
+
````
|
|
685
|
+
"""
|
|
686
|
+
return self._record.sha256
|
|
687
|
+
|
|
688
|
+
@sha256.setter
|
|
689
|
+
def sha256(self, value: Optional[bytes]) -> None:
|
|
690
|
+
self._record.sha256 = value
|
|
691
|
+
|
|
692
|
+
@property
|
|
693
|
+
def size(self) -> Optional[int]:
|
|
694
|
+
"""
|
|
695
|
+
Optionally the size of the package archive in bytes.
|
|
696
|
+
|
|
697
|
+
Examples
|
|
698
|
+
--------
|
|
699
|
+
```python
|
|
700
|
+
>>> from rattler import PrefixRecord
|
|
701
|
+
>>> record = PrefixRecord.from_path(
|
|
702
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
703
|
+
... )
|
|
704
|
+
>>> record.size
|
|
705
|
+
669941
|
|
706
|
+
>>> record.size = 42
|
|
707
|
+
>>> record.size
|
|
708
|
+
42
|
|
709
|
+
>>> record.size = None
|
|
710
|
+
>>> record.size is None
|
|
711
|
+
True
|
|
712
|
+
>>>
|
|
713
|
+
```
|
|
714
|
+
"""
|
|
715
|
+
return self._record.size
|
|
716
|
+
|
|
717
|
+
@size.setter
|
|
718
|
+
def size(self, value: Optional[int]) -> None:
|
|
719
|
+
self._record.size = value
|
|
720
|
+
|
|
721
|
+
@property
|
|
722
|
+
def subdir(self) -> str:
|
|
723
|
+
"""
|
|
724
|
+
The subdirectory where the package can be found.
|
|
725
|
+
|
|
726
|
+
Examples
|
|
727
|
+
--------
|
|
728
|
+
```python
|
|
729
|
+
>>> from rattler import PrefixRecord
|
|
730
|
+
>>> record = PrefixRecord.from_path(
|
|
731
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
732
|
+
... )
|
|
733
|
+
>>> record.subdir
|
|
734
|
+
'win-64'
|
|
735
|
+
>>> record.subdir = "linux-64"
|
|
736
|
+
>>> record.subdir
|
|
737
|
+
'linux-64'
|
|
738
|
+
>>>
|
|
739
|
+
```
|
|
740
|
+
"""
|
|
741
|
+
return self._record.subdir
|
|
742
|
+
|
|
743
|
+
@subdir.setter
|
|
744
|
+
def subdir(self, value: str) -> None:
|
|
745
|
+
self._record.subdir = value
|
|
746
|
+
|
|
747
|
+
@property
|
|
748
|
+
def timestamp(self) -> Optional[datetime.datetime]:
|
|
749
|
+
"""
|
|
750
|
+
The date this entry was created.
|
|
751
|
+
|
|
752
|
+
Examples
|
|
753
|
+
--------
|
|
754
|
+
```python
|
|
755
|
+
>>> from rattler import PrefixRecord
|
|
756
|
+
>>> import datetime
|
|
757
|
+
>>> record = PrefixRecord.from_path(
|
|
758
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
759
|
+
... )
|
|
760
|
+
>>> record.timestamp
|
|
761
|
+
datetime.datetime(2022, 11, 17, 15, 7, 19, 781000, tzinfo=datetime.timezone.utc)
|
|
762
|
+
>>> new_time = datetime.datetime(2023, 1, 1, tzinfo=datetime.timezone.utc)
|
|
763
|
+
>>> record.timestamp = new_time
|
|
764
|
+
>>> record.timestamp
|
|
765
|
+
datetime.datetime(2023, 1, 1, 0, 0, tzinfo=datetime.timezone.utc)
|
|
766
|
+
>>> record.timestamp = None
|
|
767
|
+
>>> record.timestamp is None
|
|
768
|
+
True
|
|
769
|
+
>>>
|
|
770
|
+
```
|
|
771
|
+
"""
|
|
772
|
+
if self._record.timestamp:
|
|
773
|
+
return datetime.datetime.fromtimestamp(self._record.timestamp / 1000.0, tz=datetime.timezone.utc)
|
|
774
|
+
|
|
775
|
+
return self._record.timestamp
|
|
776
|
+
|
|
777
|
+
@timestamp.setter
|
|
778
|
+
def timestamp(self, value: Optional[datetime.datetime]) -> None:
|
|
779
|
+
if value is not None:
|
|
780
|
+
self._record.timestamp = int(value.timestamp() * 1000)
|
|
781
|
+
else:
|
|
782
|
+
self._record.timestamp = None
|
|
783
|
+
|
|
784
|
+
@property
|
|
785
|
+
def track_features(self) -> List[str]:
|
|
786
|
+
"""
|
|
787
|
+
Track features are nowadays only used to downweight
|
|
788
|
+
packages (ie. give them less priority).
|
|
789
|
+
To that effect, the number of track features is
|
|
790
|
+
counted (number of commas) and the package is downweighted
|
|
791
|
+
by the number of track_features.
|
|
792
|
+
|
|
793
|
+
Examples
|
|
794
|
+
--------
|
|
795
|
+
```python
|
|
796
|
+
>>> from rattler import PrefixRecord
|
|
797
|
+
>>> record = PrefixRecord.from_path(
|
|
798
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
799
|
+
... )
|
|
800
|
+
>>> record.track_features
|
|
801
|
+
[]
|
|
802
|
+
>>> record.track_features = ["feature1", "feature2"]
|
|
803
|
+
>>> record.track_features
|
|
804
|
+
['feature1', 'feature2']
|
|
805
|
+
>>>
|
|
806
|
+
```
|
|
807
|
+
"""
|
|
808
|
+
return self._record.track_features
|
|
809
|
+
|
|
810
|
+
@track_features.setter
|
|
811
|
+
def track_features(self, value: List[str]) -> None:
|
|
812
|
+
self._record.track_features = value
|
|
813
|
+
|
|
814
|
+
@property
|
|
815
|
+
def version(self) -> VersionWithSource:
|
|
816
|
+
"""
|
|
817
|
+
The version of the package.
|
|
818
|
+
|
|
819
|
+
Examples
|
|
820
|
+
--------
|
|
821
|
+
```python
|
|
822
|
+
>>> from rattler import PrefixRecord, VersionWithSource
|
|
823
|
+
>>> record = PrefixRecord.from_path(
|
|
824
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
825
|
+
... )
|
|
826
|
+
>>> record.version
|
|
827
|
+
VersionWithSource(version="3.40.0", source="3.40.0")
|
|
828
|
+
>>> record.version = VersionWithSource("1.0.0")
|
|
829
|
+
>>> record.version
|
|
830
|
+
VersionWithSource(version="1.0.0", source="1.0.0")
|
|
831
|
+
>>>
|
|
832
|
+
```
|
|
833
|
+
"""
|
|
834
|
+
return VersionWithSource._from_py_version(*self._record.version)
|
|
835
|
+
|
|
836
|
+
@version.setter
|
|
837
|
+
def version(self, value: VersionWithSource) -> None:
|
|
838
|
+
self._record.version = (value._version, value._source)
|
|
839
|
+
|
|
840
|
+
@property
|
|
841
|
+
def python_site_packages_path(self) -> Optional[str]:
|
|
842
|
+
"""
|
|
843
|
+
Optionally a path within the environment of the site-packages directory. This field is only
|
|
844
|
+
present for python interpreter packages.
|
|
845
|
+
This field was introduced with <https://github.com/conda/ceps/blob/main/cep-17.md>.
|
|
846
|
+
|
|
847
|
+
Examples
|
|
848
|
+
--------
|
|
849
|
+
```python
|
|
850
|
+
>>> from rattler import PrefixRecord
|
|
851
|
+
>>> record = PrefixRecord.from_path(
|
|
852
|
+
... "../test-data/conda-meta/python-3.11.9-h932a869_0_cpython.json"
|
|
853
|
+
... )
|
|
854
|
+
>>> record.python_site_packages_path
|
|
855
|
+
'lib/python3.11/site-packages'
|
|
856
|
+
>>>
|
|
857
|
+
```
|
|
858
|
+
"""
|
|
859
|
+
return self._record.python_site_packages_path
|
|
860
|
+
|
|
861
|
+
@python_site_packages_path.setter
|
|
862
|
+
def python_site_packages_path(self, value: Optional[str]) -> None:
|
|
863
|
+
"""
|
|
864
|
+
Sets the optional path within the environment of the site-packages directory.
|
|
865
|
+
Examples
|
|
866
|
+
--------
|
|
867
|
+
```python
|
|
868
|
+
>>> from rattler import PrefixRecord
|
|
869
|
+
>>> record = PrefixRecord.from_path(
|
|
870
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
871
|
+
... )
|
|
872
|
+
>>> record.python_site_packages_path
|
|
873
|
+
None
|
|
874
|
+
>>> record.python_site_packages_path = "lib/something"
|
|
875
|
+
>>> record.python_site_packages_path
|
|
876
|
+
'lib/something'
|
|
877
|
+
>>>
|
|
878
|
+
```
|
|
879
|
+
"""
|
|
880
|
+
self._record.set_python_site_packages_path(value)
|
|
881
|
+
|
|
882
|
+
def __str__(self) -> str:
|
|
883
|
+
"""
|
|
884
|
+
Returns the string representation of the PackageRecord.
|
|
885
|
+
|
|
886
|
+
Examples
|
|
887
|
+
--------
|
|
888
|
+
```python
|
|
889
|
+
>>> record = PackageRecord.from_index_json(
|
|
890
|
+
... "../test-data/conda-meta/pysocks-1.7.1-pyh0701188_6.json"
|
|
891
|
+
... )
|
|
892
|
+
>>> str(record)
|
|
893
|
+
'pysocks=1.7.1=pyh0701188_6'
|
|
894
|
+
>>>
|
|
895
|
+
```
|
|
896
|
+
"""
|
|
897
|
+
return self._record.as_str()
|
|
898
|
+
|
|
899
|
+
def __repr__(self) -> str:
|
|
900
|
+
"""
|
|
901
|
+
Returns a representation of the PackageRecord.
|
|
902
|
+
|
|
903
|
+
Examples
|
|
904
|
+
--------
|
|
905
|
+
```python
|
|
906
|
+
>>> record = PackageRecord.from_index_json(
|
|
907
|
+
... "../test-data/conda-meta/pysocks-1.7.1-pyh0701188_6.json"
|
|
908
|
+
... )
|
|
909
|
+
>>> record
|
|
910
|
+
PackageRecord("pysocks=1.7.1=pyh0701188_6")
|
|
911
|
+
>>>
|
|
912
|
+
```
|
|
913
|
+
"""
|
|
914
|
+
return f'PackageRecord("{self.__str__()}")'
|
|
915
|
+
|
|
916
|
+
def to_json(self) -> str:
|
|
917
|
+
"""
|
|
918
|
+
Convert the PackageRecord to a JSON string.
|
|
919
|
+
|
|
920
|
+
Examples
|
|
921
|
+
--------
|
|
922
|
+
```python
|
|
923
|
+
>>> import json
|
|
924
|
+
>>> record = PackageRecord.from_index_json(
|
|
925
|
+
... "../test-data/conda-meta/pysocks-1.7.1-pyh0701188_6.json"
|
|
926
|
+
... )
|
|
927
|
+
>>> json_data = record.to_json()
|
|
928
|
+
>>> isinstance(json_data, str)
|
|
929
|
+
True
|
|
930
|
+
>>> as_dict = json.loads(json_data)
|
|
931
|
+
>>> as_dict["name"]
|
|
932
|
+
'pysocks'
|
|
933
|
+
>>> as_dict["version"]
|
|
934
|
+
'1.7.1'
|
|
935
|
+
>>>
|
|
936
|
+
```
|
|
937
|
+
"""
|
|
938
|
+
return self._record.to_json()
|