Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update py-rattler readme #715

Merged
merged 3 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion py-rattler/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

84 changes: 11 additions & 73 deletions py-rattler/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,17 @@ Rattler is written in Rust and tries to provide a clean API to its functionaliti
With the primary goal in mind we aim to provide bindings to different languages to make it easy to integrate Rattler in non-rust projects.
Py-rattler is the python bindings for rattler.

## Quick-Start

Let's see an example to learn some of the functionality the library has to offer.

```python
--8<-- "examples\solve_and_install.py"
```

Py-rattler provides friendly high level functions to download dependencies and create environments.
The `solve` and `install` functions are excellent examples of such high-level functions.

## What is conda & conda-forge?

The conda ecosystem provides **cross-platform**, **binary** packages that you can use with **any programming language**.
Expand Down Expand Up @@ -65,79 +76,6 @@ $ conda install py-rattler
$ mamba install py-rattler -c conda-forge
```

## Quick-Start

Let's see an example to learn some of the functionality the library has to offer.

```python

import asyncio

from rattler import fetch_repo_data, solve, link, Channel, Platform, MatchSpec, VirtualPackage

def download_callback(done, total):
print("", end = "\r")
print(f'{done/1024/1024:.2f}MiB/{total/1024/1024:.2f}MiB', end = "\r")
if done == total:
print()

async def main():
# channel to use to get the dependencies
channel = Channel("conda-forge")

# list of dependencies to install in the env
match_specs = [
MatchSpec("python ~=3.12.*"),
MatchSpec("pip"),
MatchSpec("requests 2.31.0")
]

# list of platforms to get the repo data
platforms = [Platform.current(), Platform("noarch")]

virtual_packages = [p.into_generic() for p in VirtualPackage.current()]

cache_path = "/tmp/py-rattler-cache/"
env_path = "/tmp/env-path/env"

print("started fetching repo_data")
repo_data = await fetch_repo_data(
channels = [channel],
platforms = platforms,
cache_path = f"{cache_path}/repodata",
callback = download_callback,
)
print("finished fetching repo_data")

solved_dependencies = solve(
specs = match_specs,
available_packages = repo_data,
virtual_packages = virtual_packages,
)
print("solved required dependencies")

await link(
dependencies = solved_dependencies,
target_prefix = env_path,
cache_dir = f"{cache_path}/pkgs",
)
print(f"created environment: {env_path}")

if __name__ == "__main__":
asyncio.run(main())

```

Py-rattler provides friendly high level functions to download
dependencies and create environments. This is done through the
`fetch_repo_data`, `solve` and `link` functions.

- `fetch_repo_data` as the name implies, fetches repo data from conda registries.
- `solve` function solves the requirements to get all the packages
which would be required to create the environment.
- `link` function takes a list of solved dependencies to create an
environment.

## Next Steps

These basic first steps should have gotten you started with the library.
Expand Down
35 changes: 35 additions & 0 deletions py-rattler/examples/solve_and_install.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import asyncio
import tempfile

from rattler import solve, install, VirtualPackage


async def main() -> None:
# Start by solving the environment.
#
# Solving is the process of going from specifications of package and their
# version requirements to a list of concrete packages.
print("started solving the environment")
solved_records = await solve(
# Channels to use for solving
channels=["conda-forge"],
# The specs to solve for
specs=["python ~=3.12.0", "pip", "requests 2.31.0"],
# Virtual packages define the specifications of the environment
virtual_packages=VirtualPackage.current(),
)
print("solved required dependencies")

# Install the packages into a new environment (or updates it if it already
# existed).
env_path = tempfile.mkdtemp()
await install(
records=solved_records,
target_prefix=env_path,
)

print(f"created environment: {env_path}")


if __name__ == "__main__":
asyncio.run(main())
3 changes: 2 additions & 1 deletion py-rattler/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,14 +84,15 @@ markdown_extensions:
toc_depth: 3
permalink: "#"
- mdx_truly_sane_lists
- pymdownx.snippets

nav:
- First Steps: index.md
- References:
- core:
- fetch: fetch_repo_data.md
- solve: solver.md
- install: install.md
- install: installer.md
- channel:
- ChannelConfig: channel_config.md
- Channel: channel.md
Expand Down
4 changes: 2 additions & 2 deletions py-rattler/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pytest-xprocess = ">=0.23.0,<0.24"

[feature.test.tasks]
test = { cmd = "pytest --doctest-modules", depends_on = ["build"] }
fmt-python = "ruff format rattler"
fmt-python = "ruff format rattler examples"
fmt-rust = "cargo fmt --all"
lint-python = "ruff check ."
lint-rust = "cargo clippy --all"
Expand All @@ -48,7 +48,7 @@ type-check = { cmd = "mypy", depends_on = ["build"] }

# checks for the CI
fmt-rust-check = "cargo fmt --all --check"
fmt-python-check = "ruff format rattler --diff"
fmt-python-check = "ruff format rattler examples --diff"
fmt-check = { depends_on = ["fmt-python-check", "fmt-rust-check"] }

[feature.docs.dependencies]
Expand Down
2 changes: 1 addition & 1 deletion py-rattler/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ target-version = "py38"

[tool.mypy]
python_version = "3.8"
files = ["rattler", "tests"]
files = ["rattler", "tests", "examples"]
strict = true
enable_error_code = ["redundant-expr", "truthy-bool", "ignore-without-code"]
disable_error_code = ["empty-body"]
Expand Down
4 changes: 2 additions & 2 deletions py-rattler/rattler/install/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

async def install(
records: List[RepoDataRecord],
target_prefix: os.PathLike[str],
target_prefix: str | os.PathLike[str],
cache_dir: Optional[os.PathLike[str]] = None,
installed_packages: Optional[List[PrefixRecord]] = None,
platform: Optional[Platform] = None,
Expand Down Expand Up @@ -73,7 +73,7 @@ async def install(

await py_install(
records=records,
target_prefix=target_prefix,
target_prefix=str(target_prefix),
cache_dir=cache_dir,
installed_packages=installed_packages,
platform=platform._inner if platform is not None else None,
Expand Down
23 changes: 14 additions & 9 deletions py-rattler/rattler/solver/solver.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
from __future__ import annotations
import datetime
from typing import List, Optional, Literal
from typing import List, Optional, Literal, Sequence

from rattler import Channel, Platform
from rattler import Channel, Platform, VirtualPackage
from rattler.match_spec.match_spec import MatchSpec

from rattler.channel import ChannelPriority
Expand All @@ -18,13 +18,13 @@


async def solve(
channels: List[Channel | str],
specs: List[MatchSpec | str],
channels: Sequence[Channel | str],
specs: Sequence[MatchSpec | str],
gateway: Gateway = Gateway(),
platforms: Optional[List[Platform | PlatformLiteral]] = None,
locked_packages: Optional[List[RepoDataRecord]] = None,
pinned_packages: Optional[List[RepoDataRecord]] = None,
virtual_packages: Optional[List[GenericVirtualPackage]] = None,
platforms: Optional[Sequence[Platform | PlatformLiteral]] = None,
locked_packages: Optional[Sequence[RepoDataRecord]] = None,
pinned_packages: Optional[Sequence[RepoDataRecord]] = None,
virtual_packages: Optional[Sequence[GenericVirtualPackage | VirtualPackage]] = None,
timeout: Optional[datetime.timedelta] = None,
channel_priority: ChannelPriority = ChannelPriority.Strict,
exclude_newer: Optional[datetime.datetime] = None,
Expand Down Expand Up @@ -90,7 +90,12 @@ async def solve(
gateway=gateway._gateway,
locked_packages=[package._record for package in locked_packages or []],
pinned_packages=[package._record for package in pinned_packages or []],
virtual_packages=[v_package._generic_virtual_package for v_package in virtual_packages or []],
virtual_packages=[
v_package.into_generic()._generic_virtual_package
if isinstance(v_package, VirtualPackage)
else v_package._generic_virtual_package
for v_package in virtual_packages or []
],
channel_priority=channel_priority.value,
timeout=timeout.microseconds if timeout else None,
exclude_newer_timestamp_ms=int(exclude_newer.replace(tzinfo=datetime.timezone.utc).timestamp() * 1000)
Expand Down
Loading