Skip to content

Commit

Permalink
feat: add channel types to py-rattler (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
wolfv authored Sep 6, 2023
1 parent bb42076 commit 563fafb
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 20 deletions.
35 changes: 18 additions & 17 deletions py-rattler/Cargo.lock

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

1 change: 1 addition & 0 deletions py-rattler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ pyo3 = { version = "0.19", features = [
] }

thiserror = "1.0.44"
url = "2.4.1"

# Prevent package from thinking it's in the workspace
[workspace]
10 changes: 9 additions & 1 deletion py-rattler/rattler/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
from rattler.version import Version
from rattler.match_spec import MatchSpec, NamelessMatchSpec
from rattler.repo_data import PackageRecord
from rattler.channel import Channel, ChannelConfig

__all__ = ["Version", "MatchSpec", "NamelessMatchSpec", "PackageRecord"]
__all__ = [
"Version",
"MatchSpec",
"NamelessMatchSpec",
"PackageRecord",
"Channel",
"ChannelConfig",
]
4 changes: 4 additions & 0 deletions py-rattler/rattler/channel/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from rattler.channel.channel import Channel
from rattler.channel.channel_config import ChannelConfig

__all__ = ["Channel", "ChannelConfig"]
45 changes: 45 additions & 0 deletions py-rattler/rattler/channel/channel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from __future__ import annotations
from typing import Optional

from rattler.rattler import PyChannel
from rattler.channel.channel_config import ChannelConfig


class Channel:
def __init__(self, name: str, channel_configuration: ChannelConfig):
"""
Create a new channel.
>>> channel = Channel("conda-forge", ChannelConfig())
>>> channel
Channel(name="conda-forge", base_url="https://conda.anaconda.org/conda-forge/")
"""
self._channel = PyChannel(name, channel_configuration._channel_configuration)

@property
def name(self) -> Optional[str]:
"""
Return the name of this channel.
>>> channel = Channel("conda-forge", ChannelConfig())
>>> channel.name
'conda-forge'
"""
return self._channel.name

@property
def base_url(self) -> str:
"""
Return the base URL of this channel.
>>> channel = Channel("conda-forge", ChannelConfig())
>>> channel.base_url
'https://conda.anaconda.org/conda-forge/'
"""
return self._channel.base_url

def __repr__(self) -> str:
"""
Return a string representation of this channel.
"""
return f'Channel(name="{self.name}", base_url="{self.base_url}")'
26 changes: 26 additions & 0 deletions py-rattler/rattler/channel/channel_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from __future__ import annotations

from rattler.rattler import PyChannelConfig


class ChannelConfig:
def __init__(self, channel_alias="https://conda.anaconda.org/"):
"""
Create a new channel configuration.
>>> channel_config = ChannelConfig()
>>> channel_config
ChannelConfig(channel_alias="https://conda.anaconda.org/")
>>> channel_config = ChannelConfig("https://repo.prefix.dev/")
>>> channel_config
ChannelConfig(channel_alias="https://repo.prefix.dev/")
"""
self._channel_configuration = PyChannelConfig(channel_alias)

def __repr__(self) -> str:
"""
Return a string representation of this channel configuration.
"""
alias = self._channel_configuration.channel_alias
return f'ChannelConfig(channel_alias="{alias}")'
71 changes: 71 additions & 0 deletions py-rattler/src/channel/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use pyo3::{pyclass, pymethods};
use rattler_conda_types::{Channel, ChannelConfig};
use url::Url;

use crate::error::PyRattlerError;

#[pyclass]
#[repr(transparent)]
#[derive(Clone)]
pub struct PyChannelConfig {
pub(crate) inner: ChannelConfig,
}

#[pymethods]
impl PyChannelConfig {
#[new]
pub fn __init__(channel_alias: &str) -> pyo3::PyResult<Self> {
Ok(Self {
inner: ChannelConfig {
channel_alias: Url::parse(channel_alias).map_err(PyRattlerError::from)?,
},
})
}

/// Return the channel alias that is configured
#[getter]
fn channel_alias(&self) -> String {
self.inner.channel_alias.to_string()
}
}

#[pyclass]
#[repr(transparent)]
#[derive(Clone)]
pub struct PyChannel {
pub(crate) inner: Channel,
}

impl From<Channel> for PyChannel {
fn from(value: Channel) -> Self {
Self { inner: value }
}
}

impl From<PyChannel> for Channel {
fn from(val: PyChannel) -> Self {
val.inner
}
}

#[pymethods]
impl PyChannel {
#[new]
pub fn __init__(version: &str, config: &PyChannelConfig) -> pyo3::PyResult<Self> {
Ok(Channel::from_str(version, &config.inner)
.map(Into::into)
.map_err(PyRattlerError::from)?)
}

/// Return the name of the channel
#[getter]
fn name(&self) -> Option<String> {
self.inner.name.clone()
}

/// Return the base url of the channel
#[getter]
fn base_url(&self) -> String {
self.inner.base_url.to_string()
}
}
14 changes: 13 additions & 1 deletion py-rattler/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use pyo3::exceptions::PyException;
use pyo3::{create_exception, PyErr};
use rattler_conda_types::{InvalidPackageNameError, ParseMatchSpecError, ParseVersionError};
use rattler_conda_types::{
InvalidPackageNameError, ParseChannelError, ParseMatchSpecError, ParseVersionError,
};
use thiserror::Error;

#[derive(Error, Debug)]
Expand All @@ -12,6 +14,10 @@ pub enum PyRattlerError {
InvalidMatchSpec(#[from] ParseMatchSpecError),
#[error(transparent)]
InvalidPackageName(#[from] InvalidPackageNameError),
#[error(transparent)]
InvalidUrl(#[from] url::ParseError),
#[error(transparent)]
InvalidChannel(#[from] ParseChannelError),
}

impl From<PyRattlerError> for PyErr {
Expand All @@ -26,10 +32,16 @@ impl From<PyRattlerError> for PyErr {
PyRattlerError::InvalidPackageName(err) => {
InvalidPackageNameException::new_err(err.to_string())
}
PyRattlerError::InvalidUrl(err) => InvalidUrlException::new_err(err.to_string()),
PyRattlerError::InvalidChannel(err) => {
InvalidChannelException::new_err(err.to_string())
}
}
}
}

create_exception!(exceptions, InvalidVersionException, PyException);
create_exception!(exceptions, InvalidMatchSpecException, PyException);
create_exception!(exceptions, InvalidPackageNameException, PyException);
create_exception!(exceptions, InvalidUrlException, PyException);
create_exception!(exceptions, InvalidChannelException, PyException);
15 changes: 14 additions & 1 deletion py-rattler/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
mod channel;
mod error;
mod match_spec;
mod nameless_match_spec;
mod repo_data;
mod version;

use channel::{PyChannel, PyChannelConfig};
use error::{
InvalidMatchSpecException, InvalidPackageNameException, InvalidVersionException, PyRattlerError,
InvalidChannelException, InvalidMatchSpecException, InvalidPackageNameException,
InvalidUrlException, InvalidVersionException, PyRattlerError,
};
use match_spec::PyMatchSpec;
use nameless_match_spec::PyNamelessMatchSpec;
Expand All @@ -23,6 +26,9 @@ fn rattler(py: Python, m: &PyModule) -> PyResult<()> {

m.add_class::<PyPackageRecord>().unwrap();

m.add_class::<PyChannel>().unwrap();
m.add_class::<PyChannelConfig>().unwrap();

// Exceptions
m.add(
"InvalidVersionError",
Expand All @@ -39,6 +45,13 @@ fn rattler(py: Python, m: &PyModule) -> PyResult<()> {
py.get_type::<InvalidPackageNameException>(),
)
.unwrap();
m.add("InvalidUrlError", py.get_type::<InvalidUrlException>())
.unwrap();
m.add(
"InvalidChannelError",
py.get_type::<InvalidChannelException>(),
)
.unwrap();

Ok(())
}

0 comments on commit 563fafb

Please sign in to comment.