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,22 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from rattler.rattler import PyPatchInstructions
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PatchInstructions:
|
|
7
|
+
_patch_instructions: PyPatchInstructions
|
|
8
|
+
|
|
9
|
+
@classmethod
|
|
10
|
+
def _from_py_patch_instructions(cls, py_patch_instructions: PyPatchInstructions) -> PatchInstructions:
|
|
11
|
+
"""
|
|
12
|
+
Construct Rattler PatchInstructions from FFI PyPatchInstructions object.
|
|
13
|
+
"""
|
|
14
|
+
patch_instructions = cls.__new__(cls)
|
|
15
|
+
patch_instructions._patch_instructions = py_patch_instructions
|
|
16
|
+
return patch_instructions
|
|
17
|
+
|
|
18
|
+
def __repr__(self) -> str:
|
|
19
|
+
"""
|
|
20
|
+
Returns a representation of the PatchInstructions.
|
|
21
|
+
"""
|
|
22
|
+
return f"{type(self).__name__}()"
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from rattler.rattler import PyRecord
|
|
4
|
+
from rattler.repo_data.package_record import PackageRecord
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class RepoDataRecord(PackageRecord):
|
|
8
|
+
def __init__(self, package_record: PackageRecord, file_name: str, url: str, channel: str) -> None:
|
|
9
|
+
record = PyRecord.create_repodata_record(
|
|
10
|
+
package_record._record,
|
|
11
|
+
file_name,
|
|
12
|
+
url,
|
|
13
|
+
channel,
|
|
14
|
+
)
|
|
15
|
+
self._record = record
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def url(self) -> str:
|
|
19
|
+
"""
|
|
20
|
+
The canonical URL from where to get this package.
|
|
21
|
+
|
|
22
|
+
Examples
|
|
23
|
+
--------
|
|
24
|
+
```python
|
|
25
|
+
>>> from rattler import PrefixRecord
|
|
26
|
+
>>> record = PrefixRecord.from_path(
|
|
27
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
28
|
+
... )
|
|
29
|
+
>>> record.url
|
|
30
|
+
'https://conda.anaconda.org/conda-forge/win-64/libsqlite-3.40.0-hcfcfb64_0.tar.bz2'
|
|
31
|
+
>>>
|
|
32
|
+
```
|
|
33
|
+
"""
|
|
34
|
+
return self._record.url
|
|
35
|
+
|
|
36
|
+
@url.setter
|
|
37
|
+
def url(self, value: str) -> None:
|
|
38
|
+
"""
|
|
39
|
+
Set the canonical URL for this package.
|
|
40
|
+
|
|
41
|
+
Examples
|
|
42
|
+
--------
|
|
43
|
+
```python
|
|
44
|
+
>>> from rattler import PrefixRecord
|
|
45
|
+
>>> record = PrefixRecord.from_path(
|
|
46
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
47
|
+
... )
|
|
48
|
+
>>> record.url = "https://example.com/package.tar.bz2"
|
|
49
|
+
>>> record.url
|
|
50
|
+
'https://example.com/package.tar.bz2'
|
|
51
|
+
>>>
|
|
52
|
+
```
|
|
53
|
+
"""
|
|
54
|
+
self._record.set_url(value)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def channel(self) -> str:
|
|
58
|
+
"""
|
|
59
|
+
String representation of the channel where the
|
|
60
|
+
package comes from. This could be a URL but it
|
|
61
|
+
could also be a channel name.
|
|
62
|
+
|
|
63
|
+
Examples
|
|
64
|
+
--------
|
|
65
|
+
```python
|
|
66
|
+
>>> from rattler import PrefixRecord
|
|
67
|
+
>>> record = PrefixRecord.from_path(
|
|
68
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
69
|
+
... )
|
|
70
|
+
>>> record.channel
|
|
71
|
+
'https://conda.anaconda.org/conda-forge/win-64'
|
|
72
|
+
>>>
|
|
73
|
+
```
|
|
74
|
+
"""
|
|
75
|
+
return self._record.channel
|
|
76
|
+
|
|
77
|
+
@channel.setter
|
|
78
|
+
def channel(self, value: str) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Set the channel for this package.
|
|
81
|
+
|
|
82
|
+
Examples
|
|
83
|
+
--------
|
|
84
|
+
```python
|
|
85
|
+
>>> from rattler import PrefixRecord
|
|
86
|
+
>>> record = PrefixRecord.from_path(
|
|
87
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
88
|
+
... )
|
|
89
|
+
>>> record.channel = "conda-forge"
|
|
90
|
+
>>> record.channel
|
|
91
|
+
'conda-forge'
|
|
92
|
+
>>>
|
|
93
|
+
```
|
|
94
|
+
"""
|
|
95
|
+
self._record.set_channel(value)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def file_name(self) -> str:
|
|
99
|
+
"""
|
|
100
|
+
The filename of the package.
|
|
101
|
+
|
|
102
|
+
Examples
|
|
103
|
+
--------
|
|
104
|
+
```python
|
|
105
|
+
>>> from rattler import PrefixRecord
|
|
106
|
+
>>> record = PrefixRecord.from_path(
|
|
107
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
108
|
+
... )
|
|
109
|
+
>>> record.file_name
|
|
110
|
+
'libsqlite-3.40.0-hcfcfb64_0.tar.bz2'
|
|
111
|
+
>>>
|
|
112
|
+
```
|
|
113
|
+
"""
|
|
114
|
+
return self._record.file_name
|
|
115
|
+
|
|
116
|
+
@file_name.setter
|
|
117
|
+
def file_name(self, value: str) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Set the filename of the package.
|
|
120
|
+
|
|
121
|
+
Examples
|
|
122
|
+
--------
|
|
123
|
+
```python
|
|
124
|
+
>>> from rattler import PrefixRecord
|
|
125
|
+
>>> record = PrefixRecord.from_path(
|
|
126
|
+
... "../test-data/conda-meta/libsqlite-3.40.0-hcfcfb64_0.json"
|
|
127
|
+
... )
|
|
128
|
+
>>> record.file_name = "new-package-1.0.tar.bz2"
|
|
129
|
+
>>> record.file_name
|
|
130
|
+
'new-package-1.0.tar.bz2'
|
|
131
|
+
>>>
|
|
132
|
+
```
|
|
133
|
+
"""
|
|
134
|
+
self._record.set_file_name(value)
|
|
135
|
+
|
|
136
|
+
@classmethod
|
|
137
|
+
def _from_py_record(cls, py_record: PyRecord) -> RepoDataRecord:
|
|
138
|
+
"""
|
|
139
|
+
Construct Rattler RepoDataRecord from FFI PyRecord object.
|
|
140
|
+
"""
|
|
141
|
+
|
|
142
|
+
# quick sanity check
|
|
143
|
+
assert py_record.is_repodata_record
|
|
144
|
+
record = cls.__new__(cls)
|
|
145
|
+
record._record = py_record
|
|
146
|
+
return record
|
|
147
|
+
|
|
148
|
+
def __repr__(self) -> str:
|
|
149
|
+
"""
|
|
150
|
+
Returns a representation of the RepoDataRecord.
|
|
151
|
+
|
|
152
|
+
Examples
|
|
153
|
+
--------
|
|
154
|
+
```python
|
|
155
|
+
>>> from rattler import RepoData, Channel
|
|
156
|
+
>>> repo_data = RepoData(
|
|
157
|
+
... "../test-data/test-server/repo/noarch/repodata.json"
|
|
158
|
+
... )
|
|
159
|
+
>>> repo_data.into_repo_data(Channel("test"))[0]
|
|
160
|
+
RepoDataRecord(url="https://conda.anaconda.org/test/noarch/test-package-0.1-0.tar.bz2")
|
|
161
|
+
>>>
|
|
162
|
+
```
|
|
163
|
+
"""
|
|
164
|
+
return f'{type(self).__name__}(url="{self.url}")'
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Union, List, TYPE_CHECKING
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from os import PathLike
|
|
8
|
+
from rattler.channel import Channel
|
|
9
|
+
from rattler.repo_data import PatchInstructions, RepoDataRecord
|
|
10
|
+
|
|
11
|
+
from rattler.rattler import PyRepoData
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RepoData:
|
|
15
|
+
def __init__(self, path: Union[str, PathLike[str]]) -> None:
|
|
16
|
+
if not isinstance(path, (str, Path)):
|
|
17
|
+
raise TypeError(
|
|
18
|
+
f"RepoData constructor received unsupported type {type(path).__name__!r} for the `path` parameter"
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
self._repo_data = PyRepoData.from_path(path)
|
|
22
|
+
|
|
23
|
+
def apply_patches(self, instructions: PatchInstructions) -> None:
|
|
24
|
+
"""
|
|
25
|
+
Apply a patch to a repodata file.
|
|
26
|
+
Note that we currently do not handle revoked instructions.
|
|
27
|
+
"""
|
|
28
|
+
self._repo_data.apply_patches(instructions._patch_instructions)
|
|
29
|
+
|
|
30
|
+
def into_repo_data(self, channel: Channel) -> List[RepoDataRecord]:
|
|
31
|
+
"""
|
|
32
|
+
Builds a `List[RepoDataRecord]` from the packages in a
|
|
33
|
+
`RepoData` given the source of the data.
|
|
34
|
+
|
|
35
|
+
Examples
|
|
36
|
+
--------
|
|
37
|
+
```python
|
|
38
|
+
>>> from rattler import Channel
|
|
39
|
+
>>> repo_data = RepoData("../test-data/test-server/repo/noarch/repodata.json")
|
|
40
|
+
>>> repo_data.into_repo_data(Channel("test"))
|
|
41
|
+
[...]
|
|
42
|
+
>>>
|
|
43
|
+
```
|
|
44
|
+
"""
|
|
45
|
+
from rattler.repo_data import RepoDataRecord
|
|
46
|
+
|
|
47
|
+
return [
|
|
48
|
+
RepoDataRecord._from_py_record(record)
|
|
49
|
+
for record in PyRepoData.repo_data_to_records(self._repo_data, channel._channel)
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def _from_py_repo_data(cls, py_repo_data: PyRepoData) -> RepoData:
|
|
54
|
+
"""
|
|
55
|
+
Construct Rattler RepoData from FFI PyRepoData object.
|
|
56
|
+
"""
|
|
57
|
+
repo_data = cls.__new__(cls)
|
|
58
|
+
repo_data._repo_data = py_repo_data
|
|
59
|
+
return repo_data
|
|
60
|
+
|
|
61
|
+
def __repr__(self) -> str:
|
|
62
|
+
"""
|
|
63
|
+
Returns a representation of the RepoData.
|
|
64
|
+
|
|
65
|
+
Examples
|
|
66
|
+
--------
|
|
67
|
+
```python
|
|
68
|
+
>>> repo_data = RepoData("../test-data/test-server/repo/noarch/repodata.json")
|
|
69
|
+
>>> repo_data
|
|
70
|
+
RepoData()
|
|
71
|
+
>>>
|
|
72
|
+
```
|
|
73
|
+
"""
|
|
74
|
+
return f"{type(self).__name__}()"
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Protocol definition for custom repodata sources."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, List, Protocol, runtime_checkable
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from rattler.platform.platform import Platform
|
|
9
|
+
from rattler.package.package_name import PackageName
|
|
10
|
+
from rattler.repo_data.record import RepoDataRecord
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@runtime_checkable
|
|
14
|
+
class RepoDataSource(Protocol):
|
|
15
|
+
"""Protocol for custom repodata sources.
|
|
16
|
+
|
|
17
|
+
Implement this protocol to provide repodata records from custom sources
|
|
18
|
+
(databases, APIs, in-memory caches, etc.) that can be used alongside
|
|
19
|
+
traditional conda channels.
|
|
20
|
+
|
|
21
|
+
Note
|
|
22
|
+
----
|
|
23
|
+
Unlike channels, custom sources are **not cached** by the gateway. The gateway's
|
|
24
|
+
internal caching mechanisms only apply to channel data. If caching is needed for
|
|
25
|
+
your custom source, you must implement it yourself within your source implementation.
|
|
26
|
+
|
|
27
|
+
**Performance:** Custom sources are slower than channels because data must be
|
|
28
|
+
marshalled between Python and Rust for each request. For performance-critical
|
|
29
|
+
applications with large amounts of repodata, consider using channels when possible.
|
|
30
|
+
|
|
31
|
+
Example
|
|
32
|
+
-------
|
|
33
|
+
```python
|
|
34
|
+
from rattler import Platform, PackageName, RepoDataRecord
|
|
35
|
+
|
|
36
|
+
class MyCustomSource:
|
|
37
|
+
async def fetch_package_records(
|
|
38
|
+
self, platform: Platform, name: PackageName
|
|
39
|
+
) -> List[RepoDataRecord]:
|
|
40
|
+
# Fetch records from your custom source
|
|
41
|
+
return [...]
|
|
42
|
+
|
|
43
|
+
def package_names(self, platform: Platform) -> List[str]:
|
|
44
|
+
# Return all available package names for the platform
|
|
45
|
+
return ["numpy", "pandas", ...]
|
|
46
|
+
|
|
47
|
+
# Usage with Gateway
|
|
48
|
+
gateway = Gateway()
|
|
49
|
+
records = await gateway.query(
|
|
50
|
+
sources=[channel, MyCustomSource()], # Mix channels and custom sources
|
|
51
|
+
platforms=["linux-64"],
|
|
52
|
+
specs=["numpy"],
|
|
53
|
+
)
|
|
54
|
+
```
|
|
55
|
+
"""
|
|
56
|
+
|
|
57
|
+
async def fetch_package_records(self, platform: Platform, name: PackageName) -> List[RepoDataRecord]:
|
|
58
|
+
"""Fetch records for a specific package name and platform.
|
|
59
|
+
|
|
60
|
+
This method is called by the gateway when it needs repodata records
|
|
61
|
+
for a particular package. The platform parameter indicates which
|
|
62
|
+
subdirectory the gateway is querying for.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
platform: The platform to fetch records for (e.g., linux-64, noarch)
|
|
66
|
+
name: The package name to fetch records for
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
List of RepoDataRecord objects for the package
|
|
70
|
+
"""
|
|
71
|
+
...
|
|
72
|
+
|
|
73
|
+
def package_names(self, platform: Platform) -> List[str]:
|
|
74
|
+
"""Return all available package names for the given platform.
|
|
75
|
+
|
|
76
|
+
This is used by the gateway to know which packages are available
|
|
77
|
+
in this source for a given platform/subdirectory.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
platform: The platform to list packages for
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
List of package name strings
|
|
84
|
+
"""
|
|
85
|
+
...
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import List, Optional, Type, Literal, Iterable
|
|
5
|
+
from types import TracebackType
|
|
6
|
+
|
|
7
|
+
from rattler.match_spec.match_spec import MatchSpec
|
|
8
|
+
from rattler.channel.channel import Channel
|
|
9
|
+
from rattler.package.package_name import PackageName
|
|
10
|
+
from enum import Enum
|
|
11
|
+
|
|
12
|
+
from rattler.rattler import PySparseRepoData, PyPackageFormatSelection
|
|
13
|
+
from rattler.repo_data.record import RepoDataRecord
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PackageFormatSelection(Enum):
|
|
17
|
+
"""
|
|
18
|
+
Enum that describes what to do if both a `.tar.bz2` and a `.conda` package is available.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
ONLY_TAR_BZ2 = PyPackageFormatSelection.OnlyTarBz2
|
|
22
|
+
"""
|
|
23
|
+
Only use the `.tar.bz2` packages, ignore all `.conda` packages.
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
ONLY_CONDA = PyPackageFormatSelection.OnlyConda
|
|
27
|
+
"""
|
|
28
|
+
Only use the `.conda` packages, ignore all `.tar.bz2` packages.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
PREFER_CONDA = PyPackageFormatSelection.PreferConda
|
|
32
|
+
"""
|
|
33
|
+
Only use the `.conda` packages if there are both a `.tar.bz2` and a `.conda` package available.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
PREFER_CONDA_WITH_WHL = PyPackageFormatSelection.PreferCondaWithWhl
|
|
37
|
+
"""
|
|
38
|
+
Only use the `.conda` packages if there are both a `.tar.bz2` and a `.conda` package available.
|
|
39
|
+
Also adds `.whl` files if available.
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
BOTH = PyPackageFormatSelection.Both
|
|
43
|
+
"""
|
|
44
|
+
Use both the `.tar.bz2` and the `.conda` packages.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class SparseRepoData:
|
|
49
|
+
"""
|
|
50
|
+
A class to enable loading records from a `repodata.json` file on demand.
|
|
51
|
+
Since most of the time you don't need all the records from the `repodata.json`
|
|
52
|
+
this can help provide some significant speedups.
|
|
53
|
+
"""
|
|
54
|
+
|
|
55
|
+
def __init__(
|
|
56
|
+
self,
|
|
57
|
+
channel: Channel,
|
|
58
|
+
subdir: str,
|
|
59
|
+
path: os.PathLike[str] | str,
|
|
60
|
+
) -> None:
|
|
61
|
+
if not isinstance(channel, Channel):
|
|
62
|
+
raise TypeError(
|
|
63
|
+
"SparseRepoData constructor received unsupported type "
|
|
64
|
+
f" {type(channel).__name__!r} for the `channel` parameter"
|
|
65
|
+
)
|
|
66
|
+
if not isinstance(subdir, str):
|
|
67
|
+
raise TypeError(
|
|
68
|
+
"SparseRepoData constructor received unsupported type "
|
|
69
|
+
f" {type(subdir).__name__!r} for the `subdir` parameter"
|
|
70
|
+
)
|
|
71
|
+
if not isinstance(path, (str, Path)):
|
|
72
|
+
raise TypeError(
|
|
73
|
+
"SparseRepoData constructor received unsupported type "
|
|
74
|
+
f" {type(path).__name__!r} for the `path` parameter"
|
|
75
|
+
)
|
|
76
|
+
self._sparse = PySparseRepoData(channel._channel, subdir, str(path))
|
|
77
|
+
|
|
78
|
+
def close(self) -> None:
|
|
79
|
+
"""
|
|
80
|
+
Closes any mapped resources associated with this `SparseRepoData`
|
|
81
|
+
instance. It is good practice to call this method when you are done
|
|
82
|
+
with it. This is especially important if you want to modify or delete
|
|
83
|
+
the file from which this instance was created.
|
|
84
|
+
|
|
85
|
+
This method will release all resources associated with this instance,
|
|
86
|
+
including those that are currently being used on another thread. This
|
|
87
|
+
method will block until all resources are released.
|
|
88
|
+
|
|
89
|
+
This method has no effect if the file is already closed. Once the
|
|
90
|
+
instance is closed, any operation on the instance will raise a
|
|
91
|
+
`ValueError`.
|
|
92
|
+
|
|
93
|
+
As a convenience, it is allowed to call this method more than once;
|
|
94
|
+
only the first call, however, will have an effect.
|
|
95
|
+
|
|
96
|
+
Examples
|
|
97
|
+
--------
|
|
98
|
+
```python
|
|
99
|
+
>>> from rattler import Channel, ChannelConfig
|
|
100
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
101
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
102
|
+
>>> sparse_data = SparseRepoData(channel, "linux-64", path)
|
|
103
|
+
>>> sparse_data.close()
|
|
104
|
+
>>> sparse_data.package_names() # doctest: +IGNORE_EXCEPTION_DETAIL
|
|
105
|
+
Traceback (most recent call last):
|
|
106
|
+
ValueError: I/O operation on closed file.
|
|
107
|
+
>>>
|
|
108
|
+
```
|
|
109
|
+
"""
|
|
110
|
+
self._sparse.close()
|
|
111
|
+
|
|
112
|
+
def package_names(
|
|
113
|
+
self, package_format_selection: PackageFormatSelection = PackageFormatSelection.PREFER_CONDA
|
|
114
|
+
) -> List[str]:
|
|
115
|
+
"""
|
|
116
|
+
Returns a list over all package names in this repodata file.
|
|
117
|
+
This works by iterating over all elements in the `packages` and
|
|
118
|
+
`conda_packages` fields of the repodata and returning the unique
|
|
119
|
+
package names.
|
|
120
|
+
|
|
121
|
+
Examples
|
|
122
|
+
--------
|
|
123
|
+
```python
|
|
124
|
+
>>> from rattler import Channel, ChannelConfig
|
|
125
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
126
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
127
|
+
>>> sparse_data = SparseRepoData(channel, "linux-64", path)
|
|
128
|
+
>>> package_names = sparse_data.package_names()
|
|
129
|
+
>>> package_names
|
|
130
|
+
[...]
|
|
131
|
+
>>> isinstance(package_names[0], str)
|
|
132
|
+
True
|
|
133
|
+
>>>
|
|
134
|
+
```
|
|
135
|
+
"""
|
|
136
|
+
return self._sparse.package_names(package_format_selection.value)
|
|
137
|
+
|
|
138
|
+
def record_count(
|
|
139
|
+
self, package_format_selection: PackageFormatSelection = PackageFormatSelection.PREFER_CONDA
|
|
140
|
+
) -> int:
|
|
141
|
+
"""
|
|
142
|
+
Returns the total number of packages in this repodata file.
|
|
143
|
+
:return:
|
|
144
|
+
"""
|
|
145
|
+
return self._sparse.record_count(package_format_selection.value)
|
|
146
|
+
|
|
147
|
+
def load_records(
|
|
148
|
+
self,
|
|
149
|
+
package_name: str | PackageName,
|
|
150
|
+
package_format_selection: PackageFormatSelection = PackageFormatSelection.PREFER_CONDA,
|
|
151
|
+
) -> List[RepoDataRecord]:
|
|
152
|
+
"""
|
|
153
|
+
Returns all the records for the specified package name.
|
|
154
|
+
|
|
155
|
+
Examples
|
|
156
|
+
--------
|
|
157
|
+
```python
|
|
158
|
+
>>> from rattler import Channel, ChannelConfig, RepoDataRecord, PackageName
|
|
159
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
160
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
161
|
+
>>> sparse_data = SparseRepoData(channel, "linux-64", path)
|
|
162
|
+
>>> package_name = PackageName(sparse_data.package_names()[0])
|
|
163
|
+
>>> records = sparse_data.load_records(package_name)
|
|
164
|
+
>>> records
|
|
165
|
+
[...]
|
|
166
|
+
>>> isinstance(records[0], RepoDataRecord)
|
|
167
|
+
True
|
|
168
|
+
>>>
|
|
169
|
+
```
|
|
170
|
+
"""
|
|
171
|
+
if not isinstance(package_name, PackageName):
|
|
172
|
+
package_name = PackageName(package_name)
|
|
173
|
+
return [
|
|
174
|
+
RepoDataRecord._from_py_record(record)
|
|
175
|
+
for record in self._sparse.load_records(package_name._name, package_format_selection.value)
|
|
176
|
+
]
|
|
177
|
+
|
|
178
|
+
def load_all_records(
|
|
179
|
+
self, package_format_selection: PackageFormatSelection = PackageFormatSelection.PREFER_CONDA
|
|
180
|
+
) -> List[RepoDataRecord]:
|
|
181
|
+
"""
|
|
182
|
+
Returns all the records for the specified package name.
|
|
183
|
+
|
|
184
|
+
Examples
|
|
185
|
+
--------
|
|
186
|
+
```python
|
|
187
|
+
>>> from rattler import Channel, ChannelConfig, RepoDataRecord, PackageName
|
|
188
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
189
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
190
|
+
>>> sparse_data = SparseRepoData(channel, "linux-64", path)
|
|
191
|
+
>>> records = sparse_data.load_all_records()
|
|
192
|
+
>>> records
|
|
193
|
+
[...]
|
|
194
|
+
>>> isinstance(records[0], RepoDataRecord)
|
|
195
|
+
True
|
|
196
|
+
>>>
|
|
197
|
+
```
|
|
198
|
+
"""
|
|
199
|
+
# maybe change package_name to Union[str, PackageName]
|
|
200
|
+
return [
|
|
201
|
+
RepoDataRecord._from_py_record(record)
|
|
202
|
+
for record in self._sparse.load_all_records(package_format_selection.value)
|
|
203
|
+
]
|
|
204
|
+
|
|
205
|
+
def load_matching_records(
|
|
206
|
+
self,
|
|
207
|
+
specs: Iterable[MatchSpec],
|
|
208
|
+
package_format_selection: PackageFormatSelection = PackageFormatSelection.PREFER_CONDA,
|
|
209
|
+
) -> List[RepoDataRecord]:
|
|
210
|
+
"""
|
|
211
|
+
Returns all the records that match any of the specified MatchSpecs.
|
|
212
|
+
|
|
213
|
+
Examples
|
|
214
|
+
--------
|
|
215
|
+
```python
|
|
216
|
+
>>> from rattler import Channel, ChannelConfig, RepoDataRecord, PackageName
|
|
217
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
218
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
219
|
+
>>> sparse_data = SparseRepoData(channel, "linux-64", path)
|
|
220
|
+
>>> [record.file_name for record in sparse_data.load_matching_records([MatchSpec("* 12.5")])]
|
|
221
|
+
['cuda-version-12.5-hd4f0392_3.conda']
|
|
222
|
+
>>>
|
|
223
|
+
```
|
|
224
|
+
"""
|
|
225
|
+
return [
|
|
226
|
+
RepoDataRecord._from_py_record(record)
|
|
227
|
+
for record in self._sparse.load_matching_records(
|
|
228
|
+
[spec._match_spec for spec in specs], package_format_selection.value
|
|
229
|
+
)
|
|
230
|
+
]
|
|
231
|
+
|
|
232
|
+
@property
|
|
233
|
+
def subdir(self) -> str:
|
|
234
|
+
"""
|
|
235
|
+
Returns the subdirectory from which this repodata was loaded.
|
|
236
|
+
|
|
237
|
+
Examples
|
|
238
|
+
--------
|
|
239
|
+
```python
|
|
240
|
+
>>> from rattler import Channel, ChannelConfig
|
|
241
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
242
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
243
|
+
>>> sparse_data = SparseRepoData(channel, "linux-64", path)
|
|
244
|
+
>>> sparse_data.subdir
|
|
245
|
+
'linux-64'
|
|
246
|
+
>>>
|
|
247
|
+
```
|
|
248
|
+
"""
|
|
249
|
+
return self._sparse.subdir
|
|
250
|
+
|
|
251
|
+
@staticmethod
|
|
252
|
+
def load_records_recursive(
|
|
253
|
+
repo_data: List[SparseRepoData],
|
|
254
|
+
package_names: List[PackageName],
|
|
255
|
+
package_format_selection: PackageFormatSelection = PackageFormatSelection.PREFER_CONDA,
|
|
256
|
+
) -> List[List[RepoDataRecord]]:
|
|
257
|
+
"""
|
|
258
|
+
Given a set of [`SparseRepoData`]s load all the records
|
|
259
|
+
for the packages with the specified names and all the packages
|
|
260
|
+
these records depend on. This will parse the records for the
|
|
261
|
+
specified packages as well as all the packages these records
|
|
262
|
+
depend on.
|
|
263
|
+
|
|
264
|
+
Examples
|
|
265
|
+
--------
|
|
266
|
+
```python
|
|
267
|
+
>>> from rattler import Channel, ChannelConfig, PackageName
|
|
268
|
+
>>> channel = Channel("dummy")
|
|
269
|
+
>>> subdir = "test-data/dummy/linux-64"
|
|
270
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
271
|
+
>>> sparse_data = SparseRepoData(channel, "linux-64", path)
|
|
272
|
+
>>> package_name = PackageName("python")
|
|
273
|
+
>>> SparseRepoData.load_records_recursive([sparse_data], [package_name])
|
|
274
|
+
[...]
|
|
275
|
+
>>>
|
|
276
|
+
```
|
|
277
|
+
"""
|
|
278
|
+
return [
|
|
279
|
+
[RepoDataRecord._from_py_record(record) for record in list_of_records]
|
|
280
|
+
for list_of_records in PySparseRepoData.load_records_recursive(
|
|
281
|
+
[r._sparse for r in repo_data], [p._name for p in package_names], package_format_selection.value
|
|
282
|
+
)
|
|
283
|
+
]
|
|
284
|
+
|
|
285
|
+
@classmethod
|
|
286
|
+
def _from_py_sparse_repo_data(cls, py_sparse_repo_data: PySparseRepoData) -> SparseRepoData:
|
|
287
|
+
"""
|
|
288
|
+
Construct Rattler SparseRepoData from FFI PySparseRepoData object.
|
|
289
|
+
"""
|
|
290
|
+
sparse_repo_data = cls.__new__(cls)
|
|
291
|
+
sparse_repo_data._sparse = py_sparse_repo_data
|
|
292
|
+
return sparse_repo_data
|
|
293
|
+
|
|
294
|
+
def __repr__(self) -> str:
|
|
295
|
+
"""
|
|
296
|
+
Returns a representation of the SparseRepoData.
|
|
297
|
+
|
|
298
|
+
Examples
|
|
299
|
+
--------
|
|
300
|
+
```python
|
|
301
|
+
>>> from rattler import Channel, ChannelConfig
|
|
302
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
303
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
304
|
+
>>> sparse_data = SparseRepoData(channel, "linux-64", path)
|
|
305
|
+
>>> sparse_data
|
|
306
|
+
SparseRepoData(subdir="linux-64")
|
|
307
|
+
>>>
|
|
308
|
+
```
|
|
309
|
+
"""
|
|
310
|
+
return f'SparseRepoData(subdir="{self.subdir}")'
|
|
311
|
+
|
|
312
|
+
def __enter__(self) -> SparseRepoData:
|
|
313
|
+
"""
|
|
314
|
+
Returns the `SparseRepoData` instance itself. This is used to
|
|
315
|
+
enable the use of the `with` statement to automatically close
|
|
316
|
+
the instance when done.
|
|
317
|
+
|
|
318
|
+
Examples
|
|
319
|
+
--------
|
|
320
|
+
```python
|
|
321
|
+
>>> from rattler import Channel, ChannelConfig
|
|
322
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
323
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
324
|
+
>>> with SparseRepoData(channel, "linux-64", path) as sparse_data:
|
|
325
|
+
... print(sparse_data)
|
|
326
|
+
...
|
|
327
|
+
SparseRepoData(subdir="linux-64")
|
|
328
|
+
>>>
|
|
329
|
+
```
|
|
330
|
+
"""
|
|
331
|
+
return self
|
|
332
|
+
|
|
333
|
+
def __exit__(
|
|
334
|
+
self,
|
|
335
|
+
exctype: Optional[Type[BaseException]],
|
|
336
|
+
excinst: Optional[BaseException],
|
|
337
|
+
exctb: Optional[TracebackType],
|
|
338
|
+
) -> Literal[False]:
|
|
339
|
+
"""
|
|
340
|
+
Closes the `SparseRepoData` instance when exiting the `with` statement.
|
|
341
|
+
|
|
342
|
+
Examples
|
|
343
|
+
--------
|
|
344
|
+
```python
|
|
345
|
+
>>> from rattler import Channel, ChannelConfig
|
|
346
|
+
>>> channel = Channel("dummy", ChannelConfig())
|
|
347
|
+
>>> path = "../test-data/channels/dummy/linux-64/repodata.json"
|
|
348
|
+
>>> with SparseRepoData(channel, "linux-64", path) as sparse_data:
|
|
349
|
+
... print(sparse_data)
|
|
350
|
+
...
|
|
351
|
+
SparseRepoData(subdir="linux-64")
|
|
352
|
+
>>>
|
|
353
|
+
```
|
|
354
|
+
"""
|
|
355
|
+
self.close()
|
|
356
|
+
return False
|