diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e21fcf0..7740674 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,10 +20,9 @@ repos: - id: tox-ini-fmt args: [ "-p", "fix" ] - repo: https://github.com/tox-dev/pyproject-fmt - rev: "1.8.0" + rev: "2.0.1" hooks: - id: pyproject-fmt - additional_dependencies: [ "tox>=4.15" ] - repo: https://github.com/astral-sh/ruff-pre-commit rev: "v0.4.4" hooks: diff --git a/Cargo.lock b/Cargo.lock index 678400c..81898e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -520,7 +520,7 @@ dependencies = [ [[package]] name = "pyproject-fmt-rust" -version = "1.0.0" +version = "1.0.1" dependencies = [ "indoc", "lexical-sort", diff --git a/Cargo.toml b/Cargo.toml index 43a5423..34da13c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pyproject-fmt-rust" -version = "1.0.0" +version = "1.0.1" description = "Format pyproject.toml files" repository = "https://github.com/tox-dev/pyproject-fmt" readme = "README.md" diff --git a/pyproject.toml b/pyproject.toml index 14db1a6..17647e0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ requires = [ [project] name = "pyproject-fmt-rust" -version = "1.0.0" +version = "1.0.1" description = "Format your pyproject.toml file" readme = "README.md" keywords = [ @@ -15,7 +15,7 @@ keywords = [ ] license.file = "LICENSE.txt" authors = [ - { name = "Bernat Gabor", email = "gaborjbernat@gmail.com" }, + { name = "Bernat Gabor", email = "gaborjbernat@gmail.com" }, ] requires-python = ">=3.8" classifiers = [ @@ -51,35 +51,35 @@ module-name = "pyproject_fmt_rust._lib" python-source = "src" strip = true include = [ - "rust-toolchain.toml", + "rust-toolchain.toml", ] [tool.cibuildwheel] skip = [ - "pp*", - "*musl*", + "pp*", + "*musl*", ] [tool.ruff] line-length = 120 target-version = "py38" lint.isort = { known-first-party = [ - "pyproject_fmt_rust", + "pyproject_fmt_rust", ], required-imports = [ - "from __future__ import annotations", + "from __future__ import annotations", ] } lint.select = [ - "ALL", + "ALL", ] lint.ignore = [ - "ANN101", # no type annotation for self - "ANN401", # allow Any as type annotation - "COM812", # Conflict with formatter - "CPY", # No copyright statements - "D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible - "D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible - "ISC001", # Conflict with formatter - "S104", # Possible binding to all interface + "ANN101", # no type annotation for self + "ANN401", # allow Any as type annotation + "COM812", # Conflict with formatter + "CPY", # No copyright statements + "D203", # `one-blank-line-before-class` (D203) and `no-blank-line-before-class` (D211) are incompatible + "D212", # `multi-line-summary-first-line` (D212) and `multi-line-summary-second-line` (D213) are incompatible + "ISC001", # Conflict with formatter + "S104", # Possible binding to all interface ] lint.preview = true format.preview = true @@ -88,15 +88,15 @@ format.docstring-code-line-length = 100 [tool.ruff.lint.per-file-ignores] "tests/**/*.py" = [ - "D", # don"t care about documentation in tests - "FBT", # don"t care about booleans as positional arguments in tests - "INP001", # no implicit namespace - "PLC2701", # private import - "PLR0913", # any number of arguments in tests - "PLR0917", # any number of arguments in tests - "PLR2004", # Magic value used in comparison, consider replacing with a constant variable - "S101", # asserts allowed in tests... - "S603", # `subprocess` call: check for execution of untrusted input + "D", # don"t care about documentation in tests + "FBT", # don"t care about booleans as positional arguments in tests + "INP001", # no implicit namespace + "PLC2701", # private import + "PLR0913", # any number of arguments in tests + "PLR0917", # any number of arguments in tests + "PLR2004", # Magic value used in comparison, consider replacing with a constant variable + "S101", # asserts allowed in tests... + "S603", # `subprocess` call: check for execution of untrusted input ] [tool.codespell] @@ -105,25 +105,25 @@ count = true [tool.pytest] ini_options.testpaths = [ - "tests", + "tests", ] [tool.coverage] html.show_contexts = true html.skip_covered = false paths.source = [ - "src", - ".tox/*/.venv/lib/*/site-packages", - ".tox\\*\\.venv\\Lib\\site-packages", - ".tox/*/lib/*/site-packages", - ".tox\\*\\Lib\\site-packages", - "**/src", - "**\\src", + "src", + ".tox/*/.venv/lib/*/site-packages", + ".tox\\*\\.venv\\Lib\\site-packages", + ".tox/*/lib/*/site-packages", + ".tox\\*\\Lib\\site-packages", + "**/src", + "**\\src", ] report.fail_under = 100 run.parallel = true run.plugins = [ - "covdefaults", + "covdefaults", ] [tool.mypy] diff --git a/rust/src/main.rs b/rust/src/main.rs index c40e158..f99110f 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,7 +1,7 @@ use std::string::String; use pyo3::prelude::PyModule; -use pyo3::{pyfunction, pymodule, wrap_pyfunction, Bound, PyResult}; +use pyo3::{pyclass, pyfunction, pymethods, pymodule, wrap_pyfunction, Bound, PyResult}; use taplo::formatter::{format_syntax, Options}; use taplo::parser::parse; @@ -16,46 +16,69 @@ mod project; mod global; mod helpers; -/// Format toml file -#[pyfunction] -#[must_use] -pub fn format_toml( - content: &str, +#[pyclass(frozen, get_all)] +pub struct Settings { column_width: usize, indent: usize, keep_full_version: bool, max_supported_python: (u8, u8), min_supported_python: (u8, u8), -) -> String { +} + +#[pymethods] +impl Settings { + #[new] + #[pyo3(signature = (*, column_width, indent, keep_full_version, max_supported_python, min_supported_python ))] + const fn new( + column_width: usize, + indent: usize, + keep_full_version: bool, + max_supported_python: (u8, u8), + min_supported_python: (u8, u8), + ) -> Self { + Self { + column_width, + indent, + keep_full_version, + max_supported_python, + min_supported_python, + } + } +} + +/// Format toml file +#[must_use] +#[pyfunction] +pub fn format_toml(content: &str, opt: &Settings) -> String { let root_ast = parse(content).into_syntax().clone_for_update(); let mut tables = Tables::from_ast(&root_ast); - fix_build(&mut tables, keep_full_version); + fix_build(&mut tables, opt.keep_full_version); fix_project_table( &mut tables, - keep_full_version, - max_supported_python, - min_supported_python, + opt.keep_full_version, + opt.max_supported_python, + opt.min_supported_python, ); reorder_tables(&root_ast, &mut tables); let options = Options { - align_entries: false, // do not align by = - align_comments: true, // align inline comments - align_single_comments: true, // align comments after entries - array_trailing_comma: true, // ensure arrays finish with trailing comma - array_auto_expand: true, // arrays go to multi line for easier diffs - array_auto_collapse: false, // do not collapse for easier diffs - compact_arrays: false, // do not compact for easier diffs - compact_inline_tables: false, // do not compact for easier diffs - compact_entries: false, // do not compact for easier diffs - column_width, // always expand arrays per https://github.com/tamasfe/taplo/issues/390 + align_entries: false, // do not align by = + align_comments: true, // align inline comments + align_single_comments: true, // align comments after entries + array_trailing_comma: true, // ensure arrays finish with trailing comma + array_auto_expand: true, // arrays go to multi line for easier diffs + array_auto_collapse: false, // do not collapse for easier diffs + compact_arrays: false, // do not compact for easier diffs + compact_inline_tables: false, // do not compact for easier diffs + compact_entries: false, // do not compact for easier diffs + column_width: opt.column_width, // always expand arrays per https://github.com/tamasfe/taplo/issues/390 indent_tables: false, indent_entries: false, inline_table_expand: true, trailing_newline: true, allowed_blank_lines: 1, // one blank line to separate - indent_string: " ".repeat(indent), + indent_string: " ".repeat(opt.indent), reorder_keys: false, // respect custom order reorder_arrays: false, // for natural sorting we need to this ourselves crlf: false, @@ -71,6 +94,7 @@ pub fn format_toml( #[cfg(not(tarpaulin_include))] pub fn _lib(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(format_toml, m)?)?; + m.add_class::()?; Ok(()) } @@ -79,7 +103,7 @@ mod tests { use indoc::indoc; use rstest::rstest; - use crate::format_toml; + use crate::{format_toml, Settings}; #[rstest] #[case::simple( @@ -160,7 +184,16 @@ mod tests { #[case] keep_full_version: bool, #[case] max_supported_python: (u8, u8), ) { - let got = format_toml(start, 1, indent, keep_full_version, max_supported_python, (3, 8)); + let got = format_toml( + start, + &Settings { + column_width: 1, + indent, + keep_full_version, + max_supported_python, + min_supported_python: (3, 8), + }, + ); assert_eq!(got, expected); } } diff --git a/src/pyproject_fmt_rust/__init__.py b/src/pyproject_fmt_rust/__init__.py index cf3a5bb..629155a 100644 --- a/src/pyproject_fmt_rust/__init__.py +++ b/src/pyproject_fmt_rust/__init__.py @@ -2,8 +2,9 @@ from __future__ import annotations -from ._lib import format_toml +from ._lib import Settings, format_toml __all__ = [ + "Settings", "format_toml", ] diff --git a/src/pyproject_fmt_rust/_lib.pyi b/src/pyproject_fmt_rust/_lib.pyi index 9654253..826ce18 100644 --- a/src/pyproject_fmt_rust/_lib.pyi +++ b/src/pyproject_fmt_rust/_lib.pyi @@ -1,9 +1,22 @@ -def format_toml( # noqa: PLR0913 - content: str, - *, - column_width: int, - indent: int, - keep_full_version: bool, - max_supported_python: tuple[int, int], - min_supported_python: tuple[int, int], -) -> str: ... +class Settings: + def __init__( # noqa: PLR0913 + self, + *, + column_width: int, + indent: int, + keep_full_version: bool, + max_supported_python: tuple[int, int], + min_supported_python: tuple[int, int], + ) -> None: ... + @property + def column_width(self) -> int: ... + @property + def indent(self) -> int: ... + @property + def keep_full_version(self) -> bool: ... + @property + def max_supported_python(self) -> tuple[int, int]: ... + @property + def min_supported_python(self) -> tuple[int, int]: ... + +def format_toml(content: str, settings: Settings) -> str: ... diff --git a/tests/test_main.py b/tests/test_main.py index eee7ba8..468bdee 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -2,7 +2,7 @@ from textwrap import dedent -from pyproject_fmt_rust import format_toml +from pyproject_fmt_rust import Settings, format_toml def test_format_toml() -> None: @@ -22,14 +22,14 @@ def test_format_toml() -> None: ] """ - res = format_toml( - dedent(txt), + settings = Settings( column_width=120, indent=4, keep_full_version=True, min_supported_python=(3, 7), max_supported_python=(3, 8), ) + res = format_toml(dedent(txt), settings) expected = """\ [project]