Skip to content

Commit

Permalink
ls fspath or string (#198)
Browse files Browse the repository at this point in the history
  • Loading branch information
jessekrubin authored Feb 13, 2025
1 parent 3c4067f commit b818c90
Show file tree
Hide file tree
Showing 29 changed files with 507 additions and 160 deletions.
15 changes: 15 additions & 0 deletions Cargo.lock

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

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ members = [
"crates/ryo3-reqwest",
"crates/ryo3-same-file",
"crates/ryo3-shlex",
"crates/ryo3-size",
"crates/ryo3-sqlformat",
"crates/ryo3-tokio",
"crates/ryo3-unindent",
Expand Down Expand Up @@ -94,7 +95,7 @@ repository = "https://github.com/jessekrubin/ry"
# ryo3-*
# ======
# internal
ryo3 = { path = "./crates/ryo3", features = ["all"] }
ryo3 = { path = "./crates/ryo3", features = ["ry"] }
ryo3-dev = { path = "./crates/_ryo3-dev" }
ryo3-types = { path = "./crates/ryo3-types" }
ryo3-std = { path = "./crates/ryo3-std" }
Expand All @@ -119,6 +120,7 @@ ryo3-regex = { path = "./crates/ryo3-regex" }
ryo3-reqwest = { path = "./crates/ryo3-reqwest" }
ryo3-same-file = { path = "./crates/ryo3-same-file" }
ryo3-shlex = { path = "./crates/ryo3-shlex" }
ryo3-size = { path = "./crates/ryo3-size" }
ryo3-sqlformat = { path = "./crates/ryo3-sqlformat" }
ryo3-tokio = { path = "./crates/ryo3-tokio" }
ryo3-unindent = { path = "./crates/ryo3-unindent" }
Expand Down Expand Up @@ -150,6 +152,7 @@ serde = { version = "1.0", features = ["derive"] }
serde_bytes = "0.11.12"
serde_json = "1.0.137"
shlex = "1.3.0"
size = "0.5.0"
thiserror = "2.0.11"
tokio = { version = "1.43.0", features = ["full"] }
tracing = "0.1.41"
Expand Down
8 changes: 8 additions & 0 deletions crates/ryo3-fspath/src/fspath.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ pub struct PyFsPath {
pth: PathBuf,
}

impl PyFsPath {
pub fn new<P: AsRef<Path>>(p: P) -> Self {
Self {
pth: p.as_ref().to_path_buf(),
}
}
}

#[cfg(target_os = "windows")]
fn path2str<P: AsRef<Path>>(p: P) -> String {
// remove the `\\?\` prefix if it exists
Expand Down
5 changes: 2 additions & 3 deletions crates/ryo3-fspath/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
//! `FsPath` python module
mod fspath;

use crate::fspath::PyFsPath;
use pyo3::prelude::*;
mod fspath;
pub use fspath::PyFsPath;

pub fn pymod_add(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<PyFsPath>()?;
Expand Down
17 changes: 17 additions & 0 deletions crates/ryo3-size/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "ryo3-size"
description = "python + size crate (https://crates.io/crates/size)"
version.workspace = true
authors.workspace = true
documentation.workspace = true
edition.workspace = true
homepage.workspace = true
license.workspace = true
repository.workspace = true

[dependencies]
pyo3 = { workspace = true, features = ["experimental-inspect"] }
size.workspace = true

[lints]
workspace = true
7 changes: 7 additions & 0 deletions crates/ryo3-size/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# `ryo3-size`

python + `size` crate.

`size`:
- [crates.io](https://crates.io/crates/size)
- [docs.rs](https://docs.rs/size)
20 changes: 20 additions & 0 deletions crates/ryo3-size/src/fns.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use crate::types::{Base, Style};
use pyo3::prelude::*;

#[pyfunction]
pub fn parse_size(input: &str) -> PyResult<i64> {
size::Size::from_str(input)
.map_err(|e| pyo3::exceptions::PyValueError::new_err(format!("{e}")))
.map(|s| s.bytes())
}

/// Format a size of bytes into a human-readable string.
#[must_use]
#[pyfunction]
#[pyo3(signature = (n, *, base = None, style = None))]
pub fn fmt_size(n: i64, base: Option<Base>, style: Option<Style>) -> String {
let formatter = size::fmt::SizeFormatter::new()
.with_base(base.unwrap_or_default().0)
.with_style(style.unwrap_or_default().0);
formatter.format(n)
}
16 changes: 16 additions & 0 deletions crates/ryo3-size/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#![doc = include_str!("../README.md")]

mod fns;
mod size_formatter;
mod types;

pub use fns::*;
use pyo3::prelude::*;
use pyo3::types::PyModule;

pub fn pymod_add(m: &Bound<'_, PyModule>) -> PyResult<()> {
m.add_class::<size_formatter::PySizeFormatter>()?;
m.add_function(wrap_pyfunction!(parse_size, m)?)?;
m.add_function(wrap_pyfunction!(fmt_size, m)?)?;
Ok(())
}
41 changes: 41 additions & 0 deletions crates/ryo3-size/src/size_formatter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use crate::types::{Base, Style};
use pyo3::prelude::*;

#[pyclass(name = "SizeFormatter", module = "ry")]
pub struct PySizeFormatter {
formatter: size::fmt::SizeFormatter,
base: Base,
style: Style,
}

#[pymethods]
impl PySizeFormatter {
#[new]
#[pyo3(signature = (base = None, style = None))]
fn py_new(base: Option<Base>, style: Option<Style>) -> Self {
// fn py_new(base: Option<u8>, style: Option<&str>) -> Self {
let base = base.unwrap_or_default();
let style = style.unwrap_or_default();

let formatter = size::fmt::SizeFormatter::new()
.with_base(base.0)
.with_style(style.0);
PySizeFormatter {
formatter,
base,
style,
}
}

fn format(&self, n: i64) -> String {
self.formatter.format(n)
}

fn __repr__(&self) -> String {
format!("SizeFormatter(base: {}, style: {})", self.base, self.style)
}

fn __call__(&self, n: i64) -> String {
self.formatter.format(n)
}
}
91 changes: 91 additions & 0 deletions crates/ryo3-size/src/types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use pyo3::prelude::*;
use pyo3::types::{PyInt, PyString};
use std::fmt::Display;

pub struct Base(pub size::fmt::Base);

impl Default for Base {
fn default() -> Self {
Base(size::fmt::Base::Base10)
}
}

impl Display for Base {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
size::fmt::Base::Base2 => write!(f, "2"),
size::fmt::Base::Base10 => write!(f, "10"),
_ => write!(f, "unknown"),
}
}
}

const BASE_ERR_MSG: &str = "base must be be int(2)/int(10)";
impl FromPyObject<'_> for Base {
fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Self> {
// if is int...
if ob.is_none() {
Ok(Base::default())
} else if let Ok(i) = ob.downcast::<PyInt>() {
let base = i.extract::<u8>()?;
match base {
2 => Ok(Base(size::fmt::Base::Base2)),
10 => Ok(Base(size::fmt::Base::Base10)),
_ => Err(pyo3::exceptions::PyValueError::new_err(format!(
"{BASE_ERR_MSG} ~ given: {base}"
))),
}
} else {
Err(pyo3::exceptions::PyTypeError::new_err(BASE_ERR_MSG))
}
}
}

#[derive(Debug)]
pub struct Style(pub size::fmt::Style);

impl Default for Style {
fn default() -> Self {
Style(size::fmt::Style::Default)
}
}

const STYLE_ERR_MSG: &str =
"style must be None/'default'/'abbreviated'/'abbreviated_lowercase'/'full'/'full_lowercase'";

impl FromPyObject<'_> for Style {
fn extract_bound(ob: &Bound<'_, PyAny>) -> PyResult<Self> {
if ob.is_none() {
Ok(Style::default())
} else if let Ok(s) = ob.downcast::<PyString>() {
let s_ref = s.to_str()?;
match s_ref.to_ascii_lowercase().as_str() {
"default" => Ok(Style(size::fmt::Style::Default)),
"abbreviated" => Ok(Style(size::fmt::Style::Abbreviated)),
"abbreviated_lowercase" | "abbreviated-lowercase" => {
Ok(Style(size::fmt::Style::AbbreviatedLowercase))
}
"full" => Ok(Style(size::fmt::Style::Full)),
"full_lowercase" | "full-lowercase" => Ok(Style(size::fmt::Style::FullLowercase)),
_ => Err(pyo3::exceptions::PyValueError::new_err(format!(
"{STYLE_ERR_MSG} ~ given: {s_ref}"
))),
}
} else {
Err(pyo3::exceptions::PyTypeError::new_err(STYLE_ERR_MSG))
}
}
}

impl Display for Style {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.0 {
size::fmt::Style::Default => write!(f, "default"),
size::fmt::Style::Abbreviated => write!(f, "abbreviated"),
size::fmt::Style::AbbreviatedLowercase => write!(f, "abbreviated_lowercase"),
size::fmt::Style::Full => write!(f, "full"),
size::fmt::Style::FullLowercase => write!(f, "full_lowercase"),
_ => write!(f, "unknown"),
}
}
}
11 changes: 9 additions & 2 deletions crates/ryo3/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ ryo3-regex = { workspace = true, optional = true }
ryo3-reqwest = { workspace = true, optional = true }
ryo3-same-file = { workspace = true, optional = true }
ryo3-shlex = { workspace = true, optional = true }
ryo3-size = { workspace = true, optional = true }
ryo3-sqlformat = { workspace = true, optional = true }
ryo3-tokio = { workspace = true, optional = true }
ryo3-unindent = { workspace = true, optional = true }
Expand All @@ -54,23 +55,26 @@ ryo3-macros.workspace = true
pyo3-async-runtimes.workspace = true

[features]
default = ["shlex", "jiter"]
default = []
all = [
"brotli",
"bytes",
"bzip2",
"dirs",
"flate2",
"bytes",
"fnv",
"globset",
"heck",
"http",
"jiff",
"jiter",
"jiter",
"regex",
"reqwest",
"same-file",
"shlex",
"shlex",
"size",
"sqlformat",
"tokio",
"unindent",
Expand All @@ -80,6 +84,8 @@ all = [
"xxhash",
"zstd",
]
# ry
ry = ["all"] # `ry` uses all features

brotli = ["dep:ryo3-brotli"]
bzip2 = ["dep:ryo3-bzip2"]
Expand All @@ -96,6 +102,7 @@ regex = ["dep:ryo3-regex", "ryo3-which/regex"]
reqwest = ["dep:ryo3-reqwest", "http", "url", "bytes"]
same-file = ["dep:ryo3-same-file"]
shlex = ["dep:ryo3-shlex"]
size = ["dep:ryo3-size"]
sqlformat = ["dep:ryo3-sqlformat"]
tokio = ["dep:ryo3-tokio"]
unindent = ["dep:ryo3-unindent"]
Expand Down
17 changes: 0 additions & 17 deletions crates/ryo3/src/fmts/mod.rs

This file was deleted.

Loading

0 comments on commit b818c90

Please sign in to comment.