Skip to content

Commit

Permalink
Support picking of several structs
Browse files Browse the repository at this point in the history
  • Loading branch information
jessekrubin committed Mar 10, 2025
1 parent 9839781 commit 839b721
Show file tree
Hide file tree
Showing 23 changed files with 293 additions and 37 deletions.
7 changes: 6 additions & 1 deletion crates/ryo3-bytes/src/bytes_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
use crate::bytes::PyBytes;
use pyo3::prelude::*;
use pyo3::types::{PyString, PyType};
use pyo3::types::{PyString, PyTuple, PyType};
use pyo3::IntoPyObjectExt;
use std::hash::Hash;

#[pymethods]
impl PyBytes {
fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
let pybytes = pyo3::types::PyBytes::new(py, self.as_ref()).into_bound_py_any(py)?;
PyTuple::new(py, vec![pybytes])
}

/// Hash bytes
fn __hash__(&self) -> u64 {
// STD-HASHER VERSION
Expand Down
2 changes: 1 addition & 1 deletion crates/ryo3-bytes/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ pub fn pymod_add(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyBytes>()?;

// rename bytes module to `ry`
m.getattr("Bytes")?.setattr("__module__", "ryo3")?;
m.getattr("Bytes")?.setattr("__module__", "ry.ryo3")?;

Ok(())
}
8 changes: 6 additions & 2 deletions crates/ryo3-fspath/src/fspath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ const MAIN_SEPARATOR: char = std::path::MAIN_SEPARATOR;

type ArcPathBuf = std::sync::Arc<PathBuf>;

#[pyclass(name = "FsPath", module = "ryo3", frozen)]
#[pyclass(name = "FsPath", module = "ry", frozen)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PyFsPath {
// pth: PathBuf,
pth: ArcPathBuf,
}

Expand Down Expand Up @@ -68,6 +67,11 @@ impl PyFsPath {
}
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
let os_str = self.pth.as_os_str();
PyTuple::new(py, vec![os_str])
}

fn string(&self) -> String {
path2str(self.path())
}
Expand Down
4 changes: 2 additions & 2 deletions crates/ryo3-globset/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ fn glob(
name = "globster",
signature = (patterns, /, *, case_insensitive=None, literal_separator=None, backslash_escape=None)
)]
fn globster_fn(
fn py_globster(
patterns: StringOrStrings,
case_insensitive: Option<bool>,
literal_separator: Option<bool>,
Expand All @@ -311,7 +311,7 @@ fn globster_fn(

pub fn pymod_add(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_function(wrap_pyfunction!(glob, m)?)?;
m.add_function(wrap_pyfunction!(globster_fn, m)?)?;
m.add_function(wrap_pyfunction!(py_globster, m)?)?;
m.add_class::<PyGlob>()?;
m.add_class::<PyGlobSet>()?;
m.add_class::<PyGlobster>()?;
Expand Down
24 changes: 22 additions & 2 deletions crates/ryo3-http/src/headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ use crate::PyHeadersLike;
use http::header::HeaderMap;
use pyo3::exceptions::PyRuntimeError;
use pyo3::prelude::*;
use pyo3::types::PyString;
use pyo3::types::{PyBytes, PyDict, PyString, PyTuple};
use std::collections::HashMap;

#[pyclass(name = "Headers", module = "ry.ryo3.http")]
#[pyclass(name = "Headers", module = "ry")]
#[derive(Clone, Debug)]
pub struct PyHeaders(pub HeaderMap);

Expand Down Expand Up @@ -42,6 +42,11 @@ impl PyHeaders {
Ok(Self(headers))
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
let dict = self.asdict(py)?;
PyTuple::new(py, vec![dict])
}

/// Return struct Debug-string
#[must_use]
pub fn __dbg__(&self) -> String {
Expand Down Expand Up @@ -278,6 +283,21 @@ impl PyHeaders {
Ok(PyHeaders(headers))
}

fn asdict<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyDict>> {
let d = PyDict::new(py);

for (k, v) in &self.0 {
let k = k.as_str();
if let Ok(vstr) = v.to_str() {
d.set_item(k, vstr)?;
} else {
let pybytes = PyBytes::new(py, v.as_bytes());
d.set_item(k, pybytes)?;
}
}
Ok(d)
}

// pub fn __ior__<'py>(
// mut slf: PyRefMut<'py, Self>,
// other: &PyHeaders,
Expand Down
5 changes: 5 additions & 0 deletions crates/ryo3-http/src/status_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use pyo3::prelude::*;
use pyo3::pyclass::CompareOp;
use pyo3::types::PyTuple;

#[pyclass(name = "HttpStatus", module = "ry.ryo3.http", frozen)]
#[derive(Clone, Debug)]
Expand All @@ -17,6 +18,10 @@ impl PyHttpStatus {
})?))
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(py, [self.0.as_u16()])
}

#[must_use]
pub fn __str__(&self) -> String {
format!("{:?}", self.0)
Expand Down
13 changes: 12 additions & 1 deletion crates/ryo3-jiff/src/ry_date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use std::borrow::BorrowMut;
use std::fmt::Display;
use std::hash::{DefaultHasher, Hash, Hasher};
#[derive(Debug, Clone)]
#[pyclass(name = "Date", module = "ryo3", frozen)]
#[pyclass(name = "Date", module = "ry", frozen)]
pub struct RyDate(pub(crate) Date);

#[pymethods]
Expand Down Expand Up @@ -123,6 +123,17 @@ impl RyDate {
)
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
py,
vec![
self.year().into_pyobject(py)?,
self.month().into_pyobject(py)?,
self.day().into_pyobject(py)?,
],
)
}

fn sub_date(&self, other: &RyDate) -> RySpan {
RySpan::from(self.0 - other.0)
}
Expand Down
21 changes: 18 additions & 3 deletions crates/ryo3-jiff/src/ry_datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ use crate::{JiffEraYear, JiffRoundMode, JiffUnit, JiffWeekday, RyDate, RyDateTim
use jiff::civil::{DateTime, DateTimeRound, Weekday};
use jiff::Zoned;
use pyo3::basic::CompareOp;
use pyo3::intern;
use pyo3::prelude::*;
use pyo3::types::{PyDateTime, PyDict, PyType};
use pyo3::types::{PyDateTime, PyDict, PyTuple, PyType};
use pyo3::{intern, IntoPyObjectExt};
use std::borrow::BorrowMut;
use std::fmt::Display;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::str::FromStr;
#[derive(Debug, Clone)]
#[pyclass(name = "DateTime", module = "ryo3", frozen)]
#[pyclass(name = "DateTime", module = "ry", frozen)]
pub struct RyDateTime(pub(crate) DateTime);

impl From<DateTime> for RyDateTime {
Expand Down Expand Up @@ -56,6 +56,21 @@ impl RyDateTime {
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(format!("{e}")))
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
py,
vec![
self.year().into_bound_py_any(py)?,
self.month().into_bound_py_any(py)?,
self.day().into_bound_py_any(py)?,
self.hour().into_bound_py_any(py)?,
self.minute().into_bound_py_any(py)?,
self.second().into_bound_py_any(py)?,
self.subsec_nanosecond().into_bound_py_any(py)?,
],
)
}

#[expect(non_snake_case)]
#[classattr]
fn MIN() -> Self {
Expand Down
15 changes: 13 additions & 2 deletions crates/ryo3-jiff/src/ry_iso_week_date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use crate::{JiffWeekday, RyDate};
use jiff::civil::ISOWeekDate;
use jiff::Zoned;
use pyo3::prelude::*;
use pyo3::types::PyType;
use pyo3::types::{PyTuple, PyType};
use std::hash::{DefaultHasher, Hash, Hasher};

#[derive(Debug, Clone)]
#[pyclass(name = "ISOWeekDate", module = "ryo3", frozen)]
#[pyclass(name = "ISOWeekDate", module = "ry", frozen)]
pub struct RyISOWeekDate(pub(crate) ISOWeekDate);

#[pymethods]
Expand All @@ -19,6 +19,17 @@ impl RyISOWeekDate {
.map_err(map_py_value_err)
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
py,
vec![
self.year().into_pyobject(py)?,
self.week().into_pyobject(py)?,
self.weekday().into_pyobject(py)?,
],
)
}

// ========================================================================
// CLASSATTR
// ========================================================================
Expand Down
15 changes: 13 additions & 2 deletions crates/ryo3-jiff/src/ry_offset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ use crate::ry_timezone::RyTimeZone;
use jiff::tz::{Offset, OffsetArithmetic};
use pyo3::prelude::*;
use pyo3::pyclass::CompareOp;
use pyo3::types::PyType;
use pyo3::types::{PyTuple, PyType};
use pyo3::IntoPyObjectExt;
use ryo3_std::PyDuration;
use std::hash::{DefaultHasher, Hash, Hasher};

#[derive(Debug, Clone)]
#[pyclass(name = "Offset", module = "ryo3", frozen)]
#[pyclass(name = "Offset", module = "ry", frozen)]
pub struct RyOffset(pub(crate) Offset);

#[pymethods]
Expand All @@ -33,6 +34,16 @@ impl RyOffset {
}
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
py,
vec![
py.None().into_bound_py_any(py)?,
self.0.seconds().into_bound_py_any(py)?,
],
)
}

#[expect(non_snake_case)]
#[classattr]
fn MIN() -> Self {
Expand Down
18 changes: 15 additions & 3 deletions crates/ryo3-jiff/src/ry_signed_duration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ use crate::pydatetime_conversions::signed_duration_from_pyobject;
use crate::ry_span::RySpan;
use crate::JiffSignedDuration;
use jiff::{SignedDuration, Span};
use pyo3::prelude::*;

use pyo3::basic::CompareOp;
use pyo3::types::{PyAnyMethods, PyDelta, PyType};
use pyo3::{pyclass, pymethods, Bound, FromPyObject, IntoPyObject, PyAny, PyErr, PyResult, Python};
use pyo3::types::{PyAnyMethods, PyDelta, PyTuple, PyType};
use pyo3::IntoPyObjectExt;
use ryo3_std::PyDuration;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::str::FromStr;

#[derive(Debug, Clone)]
#[pyclass(name = "SignedDuration", module = "ryo3", frozen)]
#[pyclass(name = "SignedDuration", module = "ry", frozen)]
pub struct RySignedDuration(pub(crate) SignedDuration);

#[pymethods]
Expand All @@ -22,6 +24,16 @@ impl RySignedDuration {
Self(SignedDuration::new(secs, nanos))
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
py,
vec![
self.0.as_secs().into_bound_py_any(py)?,
self.0.subsec_nanos().into_bound_py_any(py)?,
],
)
}

#[expect(non_snake_case)]
#[classattr]
fn MIN() -> Self {
Expand Down
12 changes: 9 additions & 3 deletions crates/ryo3-jiff/src/ry_span.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ use crate::span_relative_to::RySpanRelativeTo;
use crate::{timespan, JiffRoundMode, JiffSpan, JiffUnit, RyDate, RyDateTime, RyZoned};
use jiff::{Span, SpanArithmetic, SpanRelativeTo, SpanRound};
use pyo3::prelude::PyAnyMethods;
use pyo3::types::{PyDelta, PyDict, PyDictMethods, PyType};
use pyo3::types::{PyDelta, PyDict, PyDictMethods, PyTuple, PyType};
use pyo3::{
intern, pyclass, pymethods, Bound, FromPyObject, IntoPyObject, PyAny, PyErr, PyResult, Python,
intern, pyclass, pymethods, Bound, FromPyObject, IntoPyObject, IntoPyObjectExt, PyAny, PyErr,
PyResult, Python,
};
use std::fmt::Display;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::str::FromStr;

#[derive(Debug, Clone)]
#[pyclass(name = "TimeSpan", module = "ryo3", frozen)]
#[pyclass(name = "TimeSpan", module = "ry", frozen)]
pub struct RySpan(pub(crate) Span);

#[pymethods]
Expand Down Expand Up @@ -53,6 +54,11 @@ impl RySpan {
fn __str__(&self) -> String {
self.0.to_string()
}
fn __getnewargs_ex__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
let args = PyTuple::empty(py).into_bound_py_any(py)?;
let kwargs = self.asdict(py)?.into_bound_py_any(py)?;
PyTuple::new(py, vec![args, kwargs])
}

#[pyo3(signature = (human=false))]
fn string(&self, human: bool) -> String {
Expand Down
13 changes: 12 additions & 1 deletion crates/ryo3-jiff/src/ry_time.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use std::borrow::BorrowMut;
use std::fmt::Display;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::str::FromStr;
#[pyclass(name = "Time", module = "ryo3", frozen)]
#[pyclass(name = "Time", module = "ry", frozen)]
#[derive(Debug, Clone)]
pub struct RyTime(pub(crate) jiff::civil::Time);

Expand All @@ -39,6 +39,17 @@ impl RyTime {
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(format!("{e}")))
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
py,
vec![
self.hour().into_pyobject(py)?,
self.minute().into_pyobject(py)?,
self.second().into_pyobject(py)?,
self.subsec_nanosecond().into_pyobject(py)?,
],
)
}
// ========================================================================
// CLASS ATTRS
// ========================================================================
Expand Down
13 changes: 11 additions & 2 deletions crates/ryo3-jiff/src/ry_timestamp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ use crate::{JiffRoundMode, JiffUnit, RyOffset};
use jiff::{Timestamp, TimestampRound, Zoned};
use pyo3::basic::CompareOp;
use pyo3::prelude::*;
use pyo3::types::PyType;
use pyo3::types::{PyTuple, PyType};
use std::borrow::BorrowMut;
use std::fmt::Display;
use std::hash::{DefaultHasher, Hash, Hasher};
use std::str::FromStr;
#[derive(Debug, Clone)]
#[pyclass(name = "Timestamp", module = "ryo3", frozen)]
#[pyclass(name = "Timestamp", module = "ry", frozen)]
pub struct RyTimestamp(pub(crate) Timestamp);

#[pymethods]
Expand All @@ -32,6 +32,15 @@ impl RyTimestamp {
.map_err(|e| PyErr::new::<pyo3::exceptions::PyValueError, _>(format!("{e}")))
}

fn __getnewargs__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
PyTuple::new(
py,
vec![
self.as_second().into_pyobject(py)?,
self.subsec_nanosecond().into_pyobject(py)?,
],
)
}
#[expect(non_snake_case)]
#[classattr]
fn MIN() -> Self {
Expand Down
Loading

0 comments on commit 839b721

Please sign in to comment.