Skip to content

Commit

Permalink
feat: update py-rattler readme (#715)
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Jun 3, 2024
1 parent 1ab3639 commit 2475096
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 88 deletions.
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 @@ -41,7 +41,7 @@ types-networkx = "*"

[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 @@ -51,7 +51,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 @@ -94,7 +94,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=int(timeout / datetime.timedelta(microseconds=1)) if timeout else None,
exclude_newer_timestamp_ms=int(exclude_newer.replace(tzinfo=datetime.timezone.utc).timestamp() * 1000)
Expand Down

0 comments on commit 2475096

Please sign in to comment.