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
rattler/shell/shell.py
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from enum import Enum
|
|
3
|
+
|
|
4
|
+
from typing import Iterable, Optional
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import os
|
|
7
|
+
from rattler.platform.platform import Platform, PlatformLiteral
|
|
8
|
+
|
|
9
|
+
from rattler.rattler import (
|
|
10
|
+
PyActivationVariables,
|
|
11
|
+
PyActivator,
|
|
12
|
+
PyShellEnum,
|
|
13
|
+
PyActivationResult,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class PathModificationBehavior(Enum):
|
|
18
|
+
"""
|
|
19
|
+
The behavior to use when modifying the PATH environment variable.
|
|
20
|
+
Prepend will add the new path to the beginning of the PATH variable.
|
|
21
|
+
Append will add the new path to the end of the PATH variable.
|
|
22
|
+
Replace will replace the entire PATH variable with the new path.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
Prepend = "prepend"
|
|
26
|
+
Append = "append"
|
|
27
|
+
Replace = "replace"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class ActivationVariables:
|
|
31
|
+
"""An object that holds the state of the current environment."""
|
|
32
|
+
|
|
33
|
+
def __init__(
|
|
34
|
+
self,
|
|
35
|
+
current_prefix: Optional[os.PathLike[str]] = None,
|
|
36
|
+
current_path: Optional[Iterable[str] | Iterable[os.PathLike[str]]] | None = None,
|
|
37
|
+
path_modification_behavior: PathModificationBehavior = PathModificationBehavior.Prepend,
|
|
38
|
+
) -> None:
|
|
39
|
+
"""
|
|
40
|
+
Construct a new ActivationVariables object.
|
|
41
|
+
|
|
42
|
+
current_prefix: The current activated conda prefix (usually
|
|
43
|
+
`os.environ["CONDA_PREFIX"]`). This prefix is going to be deactivated.
|
|
44
|
+
current_path: The current PATH environment variable (usually
|
|
45
|
+
`os.environ["PATH"].split(os.pathsep)`).
|
|
46
|
+
path_modification_behavior: The behavior to use when modifying the PATH
|
|
47
|
+
environment variable. One of "Prepend", "Append", or "Replace".
|
|
48
|
+
Defaults to "Prepend".
|
|
49
|
+
"""
|
|
50
|
+
self._activation_variables = PyActivationVariables(
|
|
51
|
+
current_prefix,
|
|
52
|
+
current_path or os.environ.get("PATH", "").split(os.pathsep),
|
|
53
|
+
path_modification_behavior.value,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
def __str__(self) -> str:
|
|
57
|
+
return self._activation_variables.as_str()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class ActivationResult:
|
|
61
|
+
"""An object that holds the result of activating a conda environment."""
|
|
62
|
+
|
|
63
|
+
_py_activation_result: PyActivationResult
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def _from_py_activation_result(cls, py_activation_result: PyActivationResult) -> ActivationResult:
|
|
67
|
+
"""Construct Rattler version from FFI PyActivationResult object."""
|
|
68
|
+
activation_result = cls.__new__(cls)
|
|
69
|
+
activation_result._py_activation_result = py_activation_result
|
|
70
|
+
return activation_result
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def path(self) -> Path:
|
|
74
|
+
"""The new PATH environment variable."""
|
|
75
|
+
return self._py_activation_result.path
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def script(self) -> str:
|
|
79
|
+
"""The script to run to activate the environment."""
|
|
80
|
+
return self._py_activation_result.script
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class Shell:
|
|
84
|
+
"""An enum of supported shells."""
|
|
85
|
+
|
|
86
|
+
bash = PyShellEnum.Bash
|
|
87
|
+
zsh = PyShellEnum.Zsh
|
|
88
|
+
fish = PyShellEnum.Fish
|
|
89
|
+
xonsh = PyShellEnum.Xonsh
|
|
90
|
+
powershell = PyShellEnum.PowerShell
|
|
91
|
+
cmd_exe = PyShellEnum.CmdExe
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def activate(
|
|
95
|
+
prefix: Path,
|
|
96
|
+
activation_variables: ActivationVariables,
|
|
97
|
+
shell: Optional[Shell] = None,
|
|
98
|
+
platform: Optional[Platform | PlatformLiteral] = None,
|
|
99
|
+
) -> ActivationResult:
|
|
100
|
+
"""
|
|
101
|
+
Return an ActivationResult object that contains the new PATH environment variable
|
|
102
|
+
and the script to run to activate the environment.
|
|
103
|
+
|
|
104
|
+
Arguments:
|
|
105
|
+
prefix: The path to the conda prefix to activate.
|
|
106
|
+
activation_variables: The current activation variables.
|
|
107
|
+
shell: The shell to generate the activation script for.
|
|
108
|
+
platform: The platform to generate the activation script for.
|
|
109
|
+
If None, the current platform is used.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
An ActivationResult object containing the new PATH environment variable
|
|
113
|
+
and the script to run to activate the environment.
|
|
114
|
+
|
|
115
|
+
Examples
|
|
116
|
+
--------
|
|
117
|
+
```python
|
|
118
|
+
>>> from rattler.shell import Shell, activate, ActivationVariables
|
|
119
|
+
>>> from rattler.platform import Platform
|
|
120
|
+
>>> from pathlib import Path
|
|
121
|
+
>>> import sys
|
|
122
|
+
>>> p = Path("/path/to/conda/prefix")
|
|
123
|
+
>>> actvars = ActivationVariables()
|
|
124
|
+
>>> a = activate(p, actvars, Shell.xonsh)
|
|
125
|
+
>>> print(a)
|
|
126
|
+
<rattler.shell.shell.ActivationResult object at ...>
|
|
127
|
+
>>>
|
|
128
|
+
```
|
|
129
|
+
"""
|
|
130
|
+
platform = Platform(platform) if isinstance(platform, str) else platform or Platform.current()
|
|
131
|
+
shell = shell or Shell.bash
|
|
132
|
+
return ActivationResult._from_py_activation_result(
|
|
133
|
+
PyActivator.activate(prefix, activation_variables._activation_variables, platform._inner, shell)
|
|
134
|
+
)
|
rattler/solver/solver.py
ADDED
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
from typing import TYPE_CHECKING, List, Literal, Optional, Sequence, Union
|
|
5
|
+
|
|
6
|
+
from rattler.channel.channel import Channel
|
|
7
|
+
from rattler.channel.channel_priority import ChannelPriority
|
|
8
|
+
from rattler.match_spec.match_spec import MatchSpec
|
|
9
|
+
from rattler.platform.platform import Platform, PlatformLiteral
|
|
10
|
+
from rattler.rattler import PyMatchSpec, py_solve, py_solve_with_sparse_repodata
|
|
11
|
+
from rattler.repo_data.gateway import Gateway, _convert_sources
|
|
12
|
+
from rattler.repo_data.record import RepoDataRecord
|
|
13
|
+
from rattler.repo_data.sparse import SparseRepoData, PackageFormatSelection
|
|
14
|
+
from rattler.virtual_package.generic import GenericVirtualPackage
|
|
15
|
+
from rattler.virtual_package.virtual_package import VirtualPackage
|
|
16
|
+
|
|
17
|
+
if TYPE_CHECKING:
|
|
18
|
+
from rattler.repo_data.source import RepoDataSource
|
|
19
|
+
|
|
20
|
+
SolveStrategy = Literal["highest", "lowest", "lowest-direct"]
|
|
21
|
+
"""Defines the strategy to use when multiple versions of a package are available during solving."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
async def solve(
|
|
25
|
+
sources: Sequence[Union[Channel, str, RepoDataSource]],
|
|
26
|
+
specs: Sequence[MatchSpec | str],
|
|
27
|
+
gateway: Gateway = Gateway(),
|
|
28
|
+
platforms: Optional[Sequence[Platform | PlatformLiteral]] = None,
|
|
29
|
+
locked_packages: Optional[Sequence[RepoDataRecord]] = None,
|
|
30
|
+
pinned_packages: Optional[Sequence[RepoDataRecord]] = None,
|
|
31
|
+
virtual_packages: Optional[Sequence[GenericVirtualPackage | VirtualPackage]] = None,
|
|
32
|
+
timeout: Optional[datetime.timedelta] = None,
|
|
33
|
+
channel_priority: ChannelPriority = ChannelPriority.Strict,
|
|
34
|
+
exclude_newer: Optional[datetime.datetime] = None,
|
|
35
|
+
strategy: SolveStrategy = "highest",
|
|
36
|
+
constraints: Optional[Sequence[MatchSpec | str]] = None,
|
|
37
|
+
) -> List[RepoDataRecord]:
|
|
38
|
+
"""
|
|
39
|
+
Resolve the dependencies and return the `RepoDataRecord`s
|
|
40
|
+
that should be present in the environment.
|
|
41
|
+
|
|
42
|
+
Arguments:
|
|
43
|
+
sources: The sources to query for the packages. Can be channels (by name, URL,
|
|
44
|
+
or Channel object) or custom RepoDataSource implementations.
|
|
45
|
+
specs: A list of matchspec to solve.
|
|
46
|
+
platforms: The platforms to query for the packages. If `None` the current platform and
|
|
47
|
+
`noarch` is used.
|
|
48
|
+
gateway: The gateway to use for acquiring repodata.
|
|
49
|
+
locked_packages: Records of packages that are previously selected.
|
|
50
|
+
If the solver encounters multiple variants of a single
|
|
51
|
+
package (identified by its name), it will sort the records
|
|
52
|
+
and select the best possible version. However, if there
|
|
53
|
+
exists a locked version it will prefer that variant instead.
|
|
54
|
+
This is useful to reduce the number of packages that are
|
|
55
|
+
updated when installing new packages. Usually you add the
|
|
56
|
+
currently installed packages or packages from a lock-file here.
|
|
57
|
+
pinned_packages: Records of packages that are previously selected and CANNOT
|
|
58
|
+
be changed. If the solver encounters multiple variants of
|
|
59
|
+
a single package (identified by its name), it will sort the
|
|
60
|
+
records and select the best possible version. However, if
|
|
61
|
+
there is a variant available in the `pinned_packages` field it
|
|
62
|
+
will always select that version no matter what even if that
|
|
63
|
+
means other packages have to be downgraded.
|
|
64
|
+
virtual_packages: A list of virtual packages considered active.
|
|
65
|
+
channel_priority: (Default = ChannelPriority.Strict) When `ChannelPriority.Strict`
|
|
66
|
+
the channel that the package is first found in will be used as
|
|
67
|
+
the only channel for that package. When `ChannelPriority.Disabled`
|
|
68
|
+
it will search for every package in every channel.
|
|
69
|
+
timeout: The maximum time the solver is allowed to run.
|
|
70
|
+
exclude_newer: Exclude any record that is newer than the given datetime.
|
|
71
|
+
strategy: The strategy to use when multiple versions of a package are available.
|
|
72
|
+
|
|
73
|
+
* `"highest"`: Select the highest compatible version of all packages.
|
|
74
|
+
* `"lowest"`: Select the lowest compatible version of all packages.
|
|
75
|
+
* `"lowest-direct"`: Select the lowest compatible version for all
|
|
76
|
+
direct dependencies but the highest compatible version of transitive
|
|
77
|
+
dependencies.
|
|
78
|
+
constraints: Additional constraints that should be satisfied by the solver.
|
|
79
|
+
Packages included in the `constraints` are not necessarily installed,
|
|
80
|
+
but they must be satisfied by the solution.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Resolved list of `RepoDataRecord`s.
|
|
84
|
+
"""
|
|
85
|
+
|
|
86
|
+
platforms = platforms if platforms is not None else [Platform.current(), Platform("noarch")]
|
|
87
|
+
|
|
88
|
+
return [
|
|
89
|
+
RepoDataRecord._from_py_record(solved_package)
|
|
90
|
+
for solved_package in await py_solve(
|
|
91
|
+
sources=_convert_sources(sources),
|
|
92
|
+
platforms=[
|
|
93
|
+
platform._inner if isinstance(platform, Platform) else Platform(platform)._inner
|
|
94
|
+
for platform in platforms
|
|
95
|
+
],
|
|
96
|
+
specs=[
|
|
97
|
+
spec._match_spec if isinstance(spec, MatchSpec) else PyMatchSpec(str(spec), True, True)
|
|
98
|
+
for spec in specs
|
|
99
|
+
],
|
|
100
|
+
gateway=gateway._gateway,
|
|
101
|
+
locked_packages=[package._record for package in locked_packages or []],
|
|
102
|
+
pinned_packages=[package._record for package in pinned_packages or []],
|
|
103
|
+
virtual_packages=[
|
|
104
|
+
v_package.into_generic()._generic_virtual_package
|
|
105
|
+
if isinstance(v_package, VirtualPackage)
|
|
106
|
+
else v_package._generic_virtual_package
|
|
107
|
+
for v_package in virtual_packages or []
|
|
108
|
+
],
|
|
109
|
+
channel_priority=channel_priority.value,
|
|
110
|
+
timeout=int(timeout / datetime.timedelta(microseconds=1)) if timeout else None,
|
|
111
|
+
exclude_newer_timestamp_ms=int(exclude_newer.replace(tzinfo=datetime.timezone.utc).timestamp() * 1000)
|
|
112
|
+
if exclude_newer
|
|
113
|
+
else None,
|
|
114
|
+
strategy=strategy,
|
|
115
|
+
constraints=[
|
|
116
|
+
constraint._match_spec
|
|
117
|
+
if isinstance(constraint, MatchSpec)
|
|
118
|
+
else PyMatchSpec(str(constraint), True, True)
|
|
119
|
+
for constraint in constraints
|
|
120
|
+
]
|
|
121
|
+
if constraints is not None
|
|
122
|
+
else [],
|
|
123
|
+
)
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
async def solve_with_sparse_repodata(
|
|
128
|
+
specs: Sequence[MatchSpec | str],
|
|
129
|
+
sparse_repodata: Sequence[SparseRepoData],
|
|
130
|
+
locked_packages: Optional[Sequence[RepoDataRecord]] = None,
|
|
131
|
+
pinned_packages: Optional[Sequence[RepoDataRecord]] = None,
|
|
132
|
+
virtual_packages: Optional[Sequence[GenericVirtualPackage | VirtualPackage]] = None,
|
|
133
|
+
timeout: Optional[datetime.timedelta] = None,
|
|
134
|
+
channel_priority: ChannelPriority = ChannelPriority.Strict,
|
|
135
|
+
exclude_newer: Optional[datetime.datetime] = None,
|
|
136
|
+
strategy: SolveStrategy = "highest",
|
|
137
|
+
constraints: Optional[Sequence[MatchSpec | str]] = None,
|
|
138
|
+
package_format_selection: PackageFormatSelection = PackageFormatSelection.PREFER_CONDA,
|
|
139
|
+
) -> List[RepoDataRecord]:
|
|
140
|
+
"""
|
|
141
|
+
Resolve the dependencies and return the `RepoDataRecord`s
|
|
142
|
+
that should be present in the environment.
|
|
143
|
+
|
|
144
|
+
This function is similar to `solve` but instead of querying for repodata
|
|
145
|
+
with a `Gateway` object this function allows you to manually pass in the
|
|
146
|
+
repodata.
|
|
147
|
+
|
|
148
|
+
Arguments:
|
|
149
|
+
specs: A list of matchspec to solve.
|
|
150
|
+
sparse_repodata: The repodata to query for the packages.
|
|
151
|
+
locked_packages: Records of packages that are previously selected.
|
|
152
|
+
If the solver encounters multiple variants of a single
|
|
153
|
+
package (identified by its name), it will sort the records
|
|
154
|
+
and select the best possible version. However, if there
|
|
155
|
+
exists a locked version it will prefer that variant instead.
|
|
156
|
+
This is useful to reduce the number of packages that are
|
|
157
|
+
updated when installing new packages. Usually you add the
|
|
158
|
+
currently installed packages or packages from a lock-file here.
|
|
159
|
+
pinned_packages: Records of packages that are previously selected and CANNOT
|
|
160
|
+
be changed. If the solver encounters multiple variants of
|
|
161
|
+
a single package (identified by its name), it will sort the
|
|
162
|
+
records and select the best possible version. However, if
|
|
163
|
+
there is a variant available in the `pinned_packages` field it
|
|
164
|
+
will always select that version no matter what even if that
|
|
165
|
+
means other packages have to be downgraded.
|
|
166
|
+
virtual_packages: A list of virtual packages considered active.
|
|
167
|
+
channel_priority: (Default = ChannelPriority.Strict) When `ChannelPriority.Strict`
|
|
168
|
+
the channel that the package is first found in will be used as
|
|
169
|
+
the only channel for that package. When `ChannelPriority.Disabled`
|
|
170
|
+
it will search for every package in every channel.
|
|
171
|
+
timeout: The maximum time the solver is allowed to run.
|
|
172
|
+
exclude_newer: Exclude any record that is newer than the given datetime.
|
|
173
|
+
strategy: The strategy to use when multiple versions of a package are available.
|
|
174
|
+
|
|
175
|
+
* `"highest"`: Select the highest compatible version of all packages.
|
|
176
|
+
* `"lowest"`: Select the lowest compatible version of all packages.
|
|
177
|
+
* `"lowest-direct"`: Select the lowest compatible version for all
|
|
178
|
+
direct dependencies but the highest compatible version of transitive
|
|
179
|
+
dependencies.
|
|
180
|
+
constraints: Additional constraints that should be satisfied by the solver.
|
|
181
|
+
Packages included in the `constraints` are not necessarily installed,
|
|
182
|
+
but they must be satisfied by the solution.
|
|
183
|
+
package_format_selection: Defines which package formats are selected
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
Resolved list of `RepoDataRecord`s.
|
|
187
|
+
"""
|
|
188
|
+
return [
|
|
189
|
+
RepoDataRecord._from_py_record(solved_package)
|
|
190
|
+
for solved_package in await py_solve_with_sparse_repodata(
|
|
191
|
+
specs=[
|
|
192
|
+
spec._match_spec if isinstance(spec, MatchSpec) else PyMatchSpec(str(spec), True, True)
|
|
193
|
+
for spec in specs
|
|
194
|
+
],
|
|
195
|
+
sparse_repodata=[package._sparse for package in sparse_repodata],
|
|
196
|
+
locked_packages=[package._record for package in locked_packages or []],
|
|
197
|
+
pinned_packages=[package._record for package in pinned_packages or []],
|
|
198
|
+
virtual_packages=[
|
|
199
|
+
v_package.into_generic()._generic_virtual_package
|
|
200
|
+
if isinstance(v_package, VirtualPackage)
|
|
201
|
+
else v_package._generic_virtual_package
|
|
202
|
+
for v_package in virtual_packages or []
|
|
203
|
+
],
|
|
204
|
+
channel_priority=channel_priority.value,
|
|
205
|
+
timeout=int(timeout / datetime.timedelta(microseconds=1)) if timeout else None,
|
|
206
|
+
package_format_selection=package_format_selection.value,
|
|
207
|
+
exclude_newer_timestamp_ms=int(exclude_newer.replace(tzinfo=datetime.timezone.utc).timestamp() * 1000)
|
|
208
|
+
if exclude_newer
|
|
209
|
+
else None,
|
|
210
|
+
strategy=strategy,
|
|
211
|
+
constraints=[
|
|
212
|
+
constraint._match_spec
|
|
213
|
+
if isinstance(constraint, MatchSpec)
|
|
214
|
+
else PyMatchSpec(str(constraint), True, True)
|
|
215
|
+
for constraint in constraints
|
|
216
|
+
]
|
|
217
|
+
if constraints is not None
|
|
218
|
+
else [],
|
|
219
|
+
)
|
|
220
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
try:
|
|
2
|
+
from rattler.rattler import get_rattler_version as _get_rattler_version
|
|
3
|
+
|
|
4
|
+
rattler_version_string = _get_rattler_version()
|
|
5
|
+
except ImportError:
|
|
6
|
+
# this is only useful for documentation
|
|
7
|
+
import warnings
|
|
8
|
+
|
|
9
|
+
warnings.warn("rattler binary missing!", stacklevel=2)
|
|
10
|
+
rattler_version_string = ""
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_rattler_version() -> str:
|
|
14
|
+
"""
|
|
15
|
+
Return the version of the Python Rattler package as a string.
|
|
16
|
+
|
|
17
|
+
If the Rattler binary is missing, returns an empty string.
|
|
18
|
+
"""
|
|
19
|
+
return rattler_version_string
|