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,69 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
|
|
4
|
+
from rattler.rattler import PyExplicitEnvironmentSpec as _PyExplicitEnvironmentSpec
|
|
5
|
+
from rattler.rattler import PyExplicitEnvironmentEntry as _PyExplicitEnvironmentEntry
|
|
6
|
+
from rattler.platform import Platform
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ExplicitEnvironmentEntry:
|
|
10
|
+
"""A wrapper around an explicit environment entry which represents a URL to a package"""
|
|
11
|
+
|
|
12
|
+
def __init__(self, inner: _PyExplicitEnvironmentEntry) -> None:
|
|
13
|
+
self._inner = inner
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def url(self) -> str:
|
|
17
|
+
"""Returns the URL of the package"""
|
|
18
|
+
return self._inner.url()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ExplicitEnvironmentSpec:
|
|
22
|
+
"""The explicit environment (e.g. env.txt) file that contains a list of all URLs in a environment"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, inner: _PyExplicitEnvironmentSpec) -> None:
|
|
25
|
+
self._inner = inner
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def from_path(cls, path: Path) -> "ExplicitEnvironmentSpec":
|
|
29
|
+
"""Parses the object from a file specified by a `path`, using a format appropriate for the file type.
|
|
30
|
+
|
|
31
|
+
For example, if the file is in text format, this function reads the data from the file at
|
|
32
|
+
the specified path, parses the text and returns the resulting object. If the file is
|
|
33
|
+
not in a parsable format or if the file could not be read, this function raises an error.
|
|
34
|
+
"""
|
|
35
|
+
return cls(_PyExplicitEnvironmentSpec.from_path(path))
|
|
36
|
+
|
|
37
|
+
@classmethod
|
|
38
|
+
def from_str(cls, content: str) -> "ExplicitEnvironmentSpec":
|
|
39
|
+
"""
|
|
40
|
+
Parses the object from a string containing the explicit environment specification
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
>>> spec = ExplicitEnvironmentSpec.from_str('''@EXPLICIT
|
|
46
|
+
... # platform: linux-64
|
|
47
|
+
... http://repo.anaconda.com/pkgs/main/linux-64/python-3.9.0-h3.tar.bz2
|
|
48
|
+
... ''')
|
|
49
|
+
>>> spec.platform
|
|
50
|
+
Platform(linux-64)
|
|
51
|
+
>>> spec.packages[0].url
|
|
52
|
+
'http://repo.anaconda.com/pkgs/main/linux-64/python-3.9.0-h3.tar.bz2'
|
|
53
|
+
>>>
|
|
54
|
+
```
|
|
55
|
+
"""
|
|
56
|
+
return cls(_PyExplicitEnvironmentSpec.from_str(content))
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def platform(self) -> Optional[Platform]:
|
|
60
|
+
"""Returns the platform specified in the explicit environment specification"""
|
|
61
|
+
platform = self._inner.platform()
|
|
62
|
+
if platform is not None:
|
|
63
|
+
return Platform._from_py_platform(platform)
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def packages(self) -> List[ExplicitEnvironmentEntry]:
|
|
68
|
+
"""Returns the environment entries (URLs) specified in the explicit environment specification"""
|
|
69
|
+
return [ExplicitEnvironmentEntry(p) for p in self._inner.packages()]
|
rattler/index/index.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
import os
|
|
5
|
+
from typing import Optional, Literal
|
|
6
|
+
|
|
7
|
+
from rattler.platform import Platform
|
|
8
|
+
from rattler.rattler import py_index_fs, py_index_s3
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class S3Credentials:
|
|
13
|
+
"""Credentials for accessing an S3 backend."""
|
|
14
|
+
|
|
15
|
+
# The endpoint URL of the S3 backend
|
|
16
|
+
endpoint_url: str
|
|
17
|
+
|
|
18
|
+
# The region of the S3 backend
|
|
19
|
+
region: str
|
|
20
|
+
|
|
21
|
+
# The access key ID for the S3 bucket.
|
|
22
|
+
access_key_id: Optional[str] = None
|
|
23
|
+
|
|
24
|
+
# The secret access key for the S3 bucket.
|
|
25
|
+
secret_access_key: Optional[str] = None
|
|
26
|
+
|
|
27
|
+
# The session token for the S3 bucket.
|
|
28
|
+
session_token: Optional[str] = None
|
|
29
|
+
|
|
30
|
+
# Defines how to address the bucket, either using virtual-hosted-style or path-style.
|
|
31
|
+
addressing_style: Literal["path", "virtual-host"] = "virtual-host"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
async def index_fs(
|
|
35
|
+
channel_directory: os.PathLike[str],
|
|
36
|
+
target_platform: Optional[Platform] = None,
|
|
37
|
+
repodata_patch: Optional[str] = None,
|
|
38
|
+
write_zst: bool = True,
|
|
39
|
+
write_shards: bool = True,
|
|
40
|
+
force: bool = False,
|
|
41
|
+
max_parallel: int | None = None,
|
|
42
|
+
) -> None:
|
|
43
|
+
"""
|
|
44
|
+
Indexes dependencies in the `channel_directory` for one or more subdirectories within said directory.
|
|
45
|
+
Will generate repodata.json files in each subdirectory containing metadata about each present package,
|
|
46
|
+
or if `target_platform` is specified will only consider the subdirectory corresponding to this platform.
|
|
47
|
+
Will always index the "noarch" subdirectory, and thus this subdirectory should always be present, because
|
|
48
|
+
conda channels at a minimum must include this subdirectory.
|
|
49
|
+
|
|
50
|
+
Arguments:
|
|
51
|
+
channel_directory: A `os.PathLike[str]` that is the directory containing subdirectories
|
|
52
|
+
of dependencies to index.
|
|
53
|
+
target_platform: A `Platform` to index dependencies for.
|
|
54
|
+
repodata_patch: The name of the conda package (expected to be in the `noarch` subdir) that should be used for repodata patching.
|
|
55
|
+
write_zst: Whether to write repodata.json.zst.
|
|
56
|
+
write_shards: Whether to write sharded repodata.
|
|
57
|
+
force: Whether to forcefully re-index all subdirs.
|
|
58
|
+
max_parallel: The maximum number of packages to process in-memory simultaneously.
|
|
59
|
+
"""
|
|
60
|
+
await py_index_fs(
|
|
61
|
+
channel_directory,
|
|
62
|
+
target_platform._inner if target_platform else target_platform,
|
|
63
|
+
repodata_patch,
|
|
64
|
+
write_zst,
|
|
65
|
+
write_shards,
|
|
66
|
+
force,
|
|
67
|
+
max_parallel,
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
async def index_s3(
|
|
72
|
+
channel_url: str,
|
|
73
|
+
credentials: Optional[S3Credentials] = None,
|
|
74
|
+
target_platform: Optional[Platform] = None,
|
|
75
|
+
repodata_patch: Optional[str] = None,
|
|
76
|
+
write_zst: bool = True,
|
|
77
|
+
write_shards: bool = True,
|
|
78
|
+
force: bool = False,
|
|
79
|
+
max_parallel: int | None = None,
|
|
80
|
+
precondition_checks: bool = True,
|
|
81
|
+
) -> None:
|
|
82
|
+
"""
|
|
83
|
+
Indexes dependencies in the `channel_url` for one or more subdirectories in the S3 directory.
|
|
84
|
+
Will generate repodata.json files in each subdirectory containing metadata about each present package,
|
|
85
|
+
or if `target_platform` is specified will only consider the subdirectory corresponding to this platform.
|
|
86
|
+
Will always index the "noarch" subdirectory, and thus this subdirectory should always be present, because
|
|
87
|
+
conda channels at a minimum must include this subdirectory.
|
|
88
|
+
|
|
89
|
+
Arguments:
|
|
90
|
+
channel_url: An S3 URL (e.g., s3://my-bucket/my-channel that containins the subdirectories
|
|
91
|
+
of dependencies to index.
|
|
92
|
+
credentials: The credentials to use for accessing the S3 bucket. If not provided, will use the default
|
|
93
|
+
credentials from the environment.
|
|
94
|
+
target_platform: A `Platform` to index dependencies for.
|
|
95
|
+
repodata_patch: The name of the conda package (expected to be in the `noarch` subdir) that should be used for repodata patching.
|
|
96
|
+
write_zst: Whether to write repodata.json.zst.
|
|
97
|
+
write_shards: Whether to write sharded repodata.
|
|
98
|
+
force: Whether to forcefully re-index all subdirs.
|
|
99
|
+
max_parallel: The maximum number of packages to process in-memory simultaneously.
|
|
100
|
+
precondition_checks: Whether to perform precondition checks before indexing on S3 buckets which helps to prevent data corruption when indexing with multiple processes at the same time. Defaults to True.
|
|
101
|
+
"""
|
|
102
|
+
await py_index_s3(
|
|
103
|
+
channel_url,
|
|
104
|
+
credentials,
|
|
105
|
+
target_platform._inner if target_platform else target_platform,
|
|
106
|
+
repodata_patch,
|
|
107
|
+
write_zst,
|
|
108
|
+
write_shards,
|
|
109
|
+
force,
|
|
110
|
+
max_parallel,
|
|
111
|
+
precondition_checks,
|
|
112
|
+
)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import os
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from rattler.match_spec import MatchSpec
|
|
6
|
+
from rattler.networking.client import Client
|
|
7
|
+
from rattler.platform.platform import Platform
|
|
8
|
+
from rattler.prefix.prefix_record import PrefixRecord
|
|
9
|
+
from rattler.repo_data.record import RepoDataRecord
|
|
10
|
+
|
|
11
|
+
from rattler.rattler import py_install
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
async def install(
|
|
15
|
+
records: List[RepoDataRecord],
|
|
16
|
+
target_prefix: str | os.PathLike[str],
|
|
17
|
+
cache_dir: Optional[os.PathLike[str]] = None,
|
|
18
|
+
installed_packages: Optional[List[PrefixRecord]] = None,
|
|
19
|
+
reinstall_packages: Optional[set[str]] = None,
|
|
20
|
+
ignored_packages: Optional[set[str]] = None,
|
|
21
|
+
platform: Optional[Platform] = None,
|
|
22
|
+
execute_link_scripts: bool = False,
|
|
23
|
+
show_progress: bool = True,
|
|
24
|
+
client: Optional[Client] = None,
|
|
25
|
+
requested_specs: Optional[List[MatchSpec]] = None,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Create an environment by downloading and linking the `dependencies` in
|
|
29
|
+
the `target_prefix` directory.
|
|
30
|
+
|
|
31
|
+
!!! warning
|
|
32
|
+
|
|
33
|
+
When `execute_link_scripts` is set to `True` the post-link and pre-unlink scripts of
|
|
34
|
+
packages will be executed. These scripts are not sandboxed and can be used to execute
|
|
35
|
+
arbitrary code. It is therefor discouraged to enable executing link scripts.
|
|
36
|
+
|
|
37
|
+
Example
|
|
38
|
+
-------
|
|
39
|
+
```python
|
|
40
|
+
>>> import asyncio
|
|
41
|
+
>>> from rattler import solve, install
|
|
42
|
+
>>> from tempfile import TemporaryDirectory
|
|
43
|
+
>>> temp_dir = TemporaryDirectory()
|
|
44
|
+
>>>
|
|
45
|
+
>>> async def main():
|
|
46
|
+
... # Solve an environment with python 3.9 for the current platform
|
|
47
|
+
... records = await solve(sources=["conda-forge"], specs=["python 3.9.*"])
|
|
48
|
+
...
|
|
49
|
+
... # Link the environment in a temporary directory (you can pass any kind of path here).
|
|
50
|
+
... await install(records, target_prefix=temp_dir.name)
|
|
51
|
+
...
|
|
52
|
+
... # That's it! The environment is now created.
|
|
53
|
+
... # You will find Python under `f"{temp_dir.name}/bin/python"` or `f"{temp_dir.name}/python.exe"` on Windows.
|
|
54
|
+
>>> asyncio.run(main())
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Arguments:
|
|
59
|
+
records: A list of solved `RepoDataRecord`s.
|
|
60
|
+
target_prefix: Path to the directory where the environment should
|
|
61
|
+
be created.
|
|
62
|
+
cache_dir: Path to directory where the dependencies will be
|
|
63
|
+
downloaded and cached.
|
|
64
|
+
installed_packages: A list of `PrefixRecord`s which are
|
|
65
|
+
already installed in the `target_prefix`. This can be obtained by loading
|
|
66
|
+
`PrefixRecord`s from `{target_prefix}/conda-meta/`.
|
|
67
|
+
If `None` is specified then the `target_prefix` will be scanned for installed
|
|
68
|
+
packages.
|
|
69
|
+
reinstall_packages: A list of package names that should be reinstalled.
|
|
70
|
+
ignored_packages: A list of package names that should be ignored (left untouched).
|
|
71
|
+
These packages will not be removed, installed, or updated.
|
|
72
|
+
platform: Target platform to create and link the
|
|
73
|
+
environment. Defaults to current platform.
|
|
74
|
+
execute_link_scripts: whether to execute the post-link and pre-unlink scripts
|
|
75
|
+
that may be part of a package. Defaults to False.
|
|
76
|
+
show_progress: If set to `True` a progress bar will be shown on the CLI.
|
|
77
|
+
client: An authenticated client to use for downloading packages. If not specified a default
|
|
78
|
+
client will be used.
|
|
79
|
+
requested_specs: A list of `MatchSpec`s that were originally requested. These will be used
|
|
80
|
+
to populate the `requested_specs` field in the generated `conda-meta/*.json` files.
|
|
81
|
+
If `None`, the `requested_specs` field will remain empty.
|
|
82
|
+
"""
|
|
83
|
+
|
|
84
|
+
await py_install(
|
|
85
|
+
records=records,
|
|
86
|
+
target_prefix=str(target_prefix),
|
|
87
|
+
cache_dir=cache_dir,
|
|
88
|
+
installed_packages=installed_packages,
|
|
89
|
+
reinstall_packages=reinstall_packages,
|
|
90
|
+
ignored_packages=ignored_packages,
|
|
91
|
+
platform=platform._inner if platform is not None else None,
|
|
92
|
+
client=client._client if client is not None else None,
|
|
93
|
+
execute_link_scripts=execute_link_scripts,
|
|
94
|
+
show_progress=show_progress,
|
|
95
|
+
requested_specs=requested_specs,
|
|
96
|
+
)
|
rattler/lock/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from rattler.lock.lock_file import LockFile
|
|
2
|
+
from rattler.lock.environment import Environment
|
|
3
|
+
from rattler.lock.channel import LockChannel
|
|
4
|
+
from rattler.lock.hash import PackageHashes
|
|
5
|
+
from rattler.lock.package import (
|
|
6
|
+
LockedPackage,
|
|
7
|
+
PypiLockedPackage,
|
|
8
|
+
CondaLockedPackage,
|
|
9
|
+
CondaLockedBinaryPackage,
|
|
10
|
+
CondaLockedSourcePackage,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"LockFile",
|
|
15
|
+
"Environment",
|
|
16
|
+
"LockChannel",
|
|
17
|
+
"PackageHashes",
|
|
18
|
+
"LockedPackage",
|
|
19
|
+
"PypiLockedPackage",
|
|
20
|
+
"CondaLockedPackage",
|
|
21
|
+
"CondaLockedBinaryPackage",
|
|
22
|
+
"CondaLockedSourcePackage",
|
|
23
|
+
]
|
rattler/lock/channel.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from rattler.rattler import PyLockChannel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class LockChannel:
|
|
7
|
+
_channel: PyLockChannel
|
|
8
|
+
|
|
9
|
+
def __init__(self, url: str) -> None:
|
|
10
|
+
"""
|
|
11
|
+
Create a new channel.
|
|
12
|
+
"""
|
|
13
|
+
self._channel = PyLockChannel(url)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def _from_py_lock_channel(cls, channel: PyLockChannel) -> LockChannel:
|
|
17
|
+
"""
|
|
18
|
+
Construct Rattler LockChannel from FFI PyLockChannel object.
|
|
19
|
+
"""
|
|
20
|
+
chan = cls.__new__(cls)
|
|
21
|
+
chan._channel = channel
|
|
22
|
+
return chan
|
|
23
|
+
|
|
24
|
+
def __str__(self) -> str:
|
|
25
|
+
"""
|
|
26
|
+
Returns a string representation of the LockChannel.
|
|
27
|
+
|
|
28
|
+
Examples
|
|
29
|
+
--------
|
|
30
|
+
```python
|
|
31
|
+
>>> channel = LockChannel("https://conda.anaconda.org/conda-forge/")
|
|
32
|
+
>>> str(channel)
|
|
33
|
+
'https://conda.anaconda.org/conda-forge/'
|
|
34
|
+
>>>
|
|
35
|
+
```
|
|
36
|
+
"""
|
|
37
|
+
return self._channel.as_str()
|
|
38
|
+
|
|
39
|
+
def __repr__(self) -> str:
|
|
40
|
+
"""
|
|
41
|
+
Returns a representation of the LockChannel.
|
|
42
|
+
|
|
43
|
+
Examples
|
|
44
|
+
--------
|
|
45
|
+
```python
|
|
46
|
+
>>> channel = LockChannel("https://conda.anaconda.org/conda-forge/")
|
|
47
|
+
>>> channel
|
|
48
|
+
LockChannel(url="https://conda.anaconda.org/conda-forge/")
|
|
49
|
+
>>>
|
|
50
|
+
```
|
|
51
|
+
"""
|
|
52
|
+
return f'LockChannel(url="{self._channel.as_str()}")'
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Dict, List, Optional
|
|
3
|
+
|
|
4
|
+
from rattler.lock.channel import LockChannel
|
|
5
|
+
from rattler.lock.package import LockedPackage, PypiLockedPackage
|
|
6
|
+
from rattler.platform.platform import Platform
|
|
7
|
+
|
|
8
|
+
from rattler.rattler import PyEnvironment
|
|
9
|
+
from rattler.repo_data.record import RepoDataRecord
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class Environment:
|
|
13
|
+
"""
|
|
14
|
+
Information about a specific environment in the lock-file.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
_env: PyEnvironment
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self, name: str, requirements: Dict[Platform, List[RepoDataRecord]], channels: List[LockChannel]
|
|
21
|
+
) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Create a new environment.
|
|
24
|
+
"""
|
|
25
|
+
self._env = PyEnvironment(
|
|
26
|
+
name=name,
|
|
27
|
+
# TODO: move this logic to rust
|
|
28
|
+
records={
|
|
29
|
+
platform._inner: [record._record for record in records] for (platform, records) in requirements.items()
|
|
30
|
+
},
|
|
31
|
+
channels=[channel._channel for channel in channels],
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
def platforms(self) -> List[Platform]:
|
|
35
|
+
"""
|
|
36
|
+
Returns all the platforms for which we have a locked-down environment.
|
|
37
|
+
|
|
38
|
+
Examples
|
|
39
|
+
--------
|
|
40
|
+
```python
|
|
41
|
+
>>> from rattler import LockFile
|
|
42
|
+
>>> lock_file = LockFile.from_path("../test-data/test.lock")
|
|
43
|
+
>>> env = lock_file.default_environment()
|
|
44
|
+
>>> env.platforms()
|
|
45
|
+
[...]
|
|
46
|
+
>>>
|
|
47
|
+
```
|
|
48
|
+
"""
|
|
49
|
+
return [Platform._from_py_platform(p) for p in self._env.platforms()]
|
|
50
|
+
|
|
51
|
+
def channels(self) -> List[LockChannel]:
|
|
52
|
+
"""
|
|
53
|
+
Returns the channels that are used by this environment.
|
|
54
|
+
Note that the order of the channels is significant.
|
|
55
|
+
The first channel is the highest priority channel.
|
|
56
|
+
|
|
57
|
+
Examples
|
|
58
|
+
--------
|
|
59
|
+
```python
|
|
60
|
+
>>> from rattler import LockFile
|
|
61
|
+
>>> lock_file = LockFile.from_path("../test-data/test.lock")
|
|
62
|
+
>>> env = lock_file.default_environment()
|
|
63
|
+
>>> env.channels()
|
|
64
|
+
[LockChannel(url="https://conda.anaconda.org/conda-forge/")]
|
|
65
|
+
>>>
|
|
66
|
+
```
|
|
67
|
+
"""
|
|
68
|
+
return [LockChannel._from_py_lock_channel(c) for c in self._env.channels()]
|
|
69
|
+
|
|
70
|
+
def packages(self, platform: Platform) -> Optional[List[LockedPackage]]:
|
|
71
|
+
"""
|
|
72
|
+
Returns all the packages for a specific platform in this environment.
|
|
73
|
+
|
|
74
|
+
Examples
|
|
75
|
+
--------
|
|
76
|
+
```python
|
|
77
|
+
>>> from rattler import Platform, LockFile
|
|
78
|
+
>>> lock_file = LockFile.from_path("../test-data/test.lock")
|
|
79
|
+
>>> env = lock_file.default_environment()
|
|
80
|
+
>>> env.packages(Platform("osx-arm64"))[0]
|
|
81
|
+
CondaLockedBinaryPackage(name='tzdata',location='https://conda.anaconda.org/conda-forge/noarch/tzdata-2024a-h0c530f3_0.conda')
|
|
82
|
+
>>>
|
|
83
|
+
```
|
|
84
|
+
"""
|
|
85
|
+
if packages := self._env.packages(platform._inner):
|
|
86
|
+
return [LockedPackage._from_py_locked_package(p) for p in packages]
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
def packages_by_platform(self) -> Dict[Platform, List[LockedPackage]]:
|
|
90
|
+
"""
|
|
91
|
+
Returns a list of all packages and platforms defined for this environment.
|
|
92
|
+
|
|
93
|
+
Examples
|
|
94
|
+
--------
|
|
95
|
+
```python
|
|
96
|
+
>>> from rattler import LockFile
|
|
97
|
+
>>> lock_file = LockFile.from_path("../test-data/test.lock")
|
|
98
|
+
>>> env = lock_file.default_environment()
|
|
99
|
+
>>> pkgs = env.packages_by_platform()
|
|
100
|
+
>>> list(pkgs.keys())
|
|
101
|
+
[Platform(...)]
|
|
102
|
+
>>>
|
|
103
|
+
```
|
|
104
|
+
"""
|
|
105
|
+
return {
|
|
106
|
+
Platform._from_py_platform(platform): [LockedPackage._from_py_locked_package(p) for p in packages]
|
|
107
|
+
for (platform, packages) in self._env.packages_by_platform()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
def pypi_packages(
|
|
111
|
+
self,
|
|
112
|
+
) -> Dict[Platform, List[PypiLockedPackage]]:
|
|
113
|
+
"""
|
|
114
|
+
Returns all pypi packages for all platforms.
|
|
115
|
+
|
|
116
|
+
Examples
|
|
117
|
+
--------
|
|
118
|
+
```python
|
|
119
|
+
>>> from rattler import LockFile, Platform
|
|
120
|
+
>>> lock_file = LockFile.from_path("../test-data/test.lock")
|
|
121
|
+
>>> env = lock_file.default_environment()
|
|
122
|
+
>>> pypi_packages = env.pypi_packages()
|
|
123
|
+
>>> pypi_packages[Platform("osx-arm64")][0]
|
|
124
|
+
PypiLockedPackage(name='charset-normalizer',location='https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl#sha256=55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6')
|
|
125
|
+
>>>
|
|
126
|
+
```
|
|
127
|
+
"""
|
|
128
|
+
return {
|
|
129
|
+
Platform._from_py_platform(platform): [PypiLockedPackage._from_py_locked_package(pypi) for pypi in pypi_tup]
|
|
130
|
+
for (platform, pypi_tup) in self._env.pypi_packages().items()
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
def conda_repodata_records(self) -> Dict[Platform, List[RepoDataRecord]]:
|
|
134
|
+
"""
|
|
135
|
+
Returns all conda packages for all platforms.
|
|
136
|
+
|
|
137
|
+
Examples
|
|
138
|
+
--------
|
|
139
|
+
```python
|
|
140
|
+
>>> from rattler import LockFile
|
|
141
|
+
>>> lock_file = LockFile.from_path("../test-data/test.lock")
|
|
142
|
+
>>> env = lock_file.default_environment()
|
|
143
|
+
>>> env.conda_repodata_records()
|
|
144
|
+
{'osx-arm64': [RepoDataRecord(...), ...]}
|
|
145
|
+
>>>
|
|
146
|
+
```
|
|
147
|
+
"""
|
|
148
|
+
return {
|
|
149
|
+
platform.name: [RepoDataRecord._from_py_record(r) for r in records]
|
|
150
|
+
for (platform, records) in self._env.conda_repodata_records().items()
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
def conda_repodata_records_for_platform(self, platform: Platform) -> Optional[List[RepoDataRecord]]:
|
|
154
|
+
"""
|
|
155
|
+
Takes all the conda packages, converts them to [`RepoDataRecord`] and returns them or
|
|
156
|
+
returns an error if the conversion failed. Returns `None` if the specified platform is not
|
|
157
|
+
defined for this environment.
|
|
158
|
+
|
|
159
|
+
Examples
|
|
160
|
+
--------
|
|
161
|
+
```python
|
|
162
|
+
>>> from rattler import LockFile, Platform
|
|
163
|
+
>>> lock_file = LockFile.from_path("../test-data/test.lock")
|
|
164
|
+
>>> env = lock_file.default_environment()
|
|
165
|
+
>>> rdr = env.conda_repodata_records_for_platform(Platform("osx-arm64"))
|
|
166
|
+
>>> rdr
|
|
167
|
+
[...]
|
|
168
|
+
>>> rdr[0]
|
|
169
|
+
RepoDataRecord(...)
|
|
170
|
+
>>>
|
|
171
|
+
```
|
|
172
|
+
"""
|
|
173
|
+
if records := self._env.conda_repodata_records_for_platform(platform._inner):
|
|
174
|
+
return [RepoDataRecord._from_py_record(r) for r in records]
|
|
175
|
+
return None
|
|
176
|
+
|
|
177
|
+
def pypi_packages_for_platform(self, platform: Platform) -> Optional[List[PypiLockedPackage]]:
|
|
178
|
+
"""
|
|
179
|
+
Returns all the pypi packages and their associated environment data for the specified
|
|
180
|
+
platform. Returns `None` if the platform is not defined for this environment.
|
|
181
|
+
|
|
182
|
+
Examples
|
|
183
|
+
--------
|
|
184
|
+
```python
|
|
185
|
+
>>> from rattler import LockFile, Platform
|
|
186
|
+
>>> lock_file = LockFile.from_path("../test-data/test.lock")
|
|
187
|
+
>>> env = lock_file.default_environment()
|
|
188
|
+
>>> osx_pypi_pkgs = env.pypi_packages_for_platform(Platform("osx-arm64"))
|
|
189
|
+
>>> osx_pypi_pkgs
|
|
190
|
+
[...]
|
|
191
|
+
>>> osx_pypi_pkgs[0]
|
|
192
|
+
PypiLockedPackage(name='charset-normalizer',location='https://files.pythonhosted.org/packages/3a/52/9f9d17c3b54dc238de384c4cb5a2ef0e27985b42a0e5cc8e8a31d918d48d/charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl#sha256=55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6')
|
|
193
|
+
>>>
|
|
194
|
+
```
|
|
195
|
+
"""
|
|
196
|
+
if data := self._env.pypi_packages_for_platform(platform._inner):
|
|
197
|
+
return [PypiLockedPackage._from_py_locked_package(pkg) for pkg in data]
|
|
198
|
+
return None
|
|
199
|
+
|
|
200
|
+
@classmethod
|
|
201
|
+
def _from_py_environment(cls, py_environment: PyEnvironment) -> Environment:
|
|
202
|
+
"""
|
|
203
|
+
Construct Rattler Environment from FFI PyEnvironment object.
|
|
204
|
+
"""
|
|
205
|
+
env = cls.__new__(cls)
|
|
206
|
+
env._env = py_environment
|
|
207
|
+
return env
|
|
208
|
+
|
|
209
|
+
def __repr__(self) -> str:
|
|
210
|
+
"""
|
|
211
|
+
Returns a representation of the Environment.
|
|
212
|
+
"""
|
|
213
|
+
return "Environment()"
|
rattler/lock/hash.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from rattler.rattler import PyPackageHashes
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class PackageHashes:
|
|
7
|
+
_hashes: PyPackageHashes
|
|
8
|
+
|
|
9
|
+
@property
|
|
10
|
+
def md5(self) -> Optional[bytes]:
|
|
11
|
+
"""
|
|
12
|
+
Returns the Sha256 hash.
|
|
13
|
+
"""
|
|
14
|
+
return self._hashes.md5
|
|
15
|
+
|
|
16
|
+
@property
|
|
17
|
+
def sha256(self) -> Optional[bytes]:
|
|
18
|
+
"""
|
|
19
|
+
Returns the Sha256 hash.
|
|
20
|
+
"""
|
|
21
|
+
return self._hashes.sha256
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def _from_py_package_hashes(cls, pkg_hashes: PyPackageHashes) -> PackageHashes:
|
|
25
|
+
"""
|
|
26
|
+
Construct Rattler PackageHashes from FFI PyPackageHashes object.
|
|
27
|
+
"""
|
|
28
|
+
hashes = cls.__new__(cls)
|
|
29
|
+
hashes._hashes = pkg_hashes
|
|
30
|
+
return hashes
|
|
31
|
+
|
|
32
|
+
def __repr__(self) -> str:
|
|
33
|
+
return "PackageHashes()"
|