Skip to content

Commit

Permalink
Addressed lint issues and more CI updates
Browse files Browse the repository at this point in the history
  • Loading branch information
scott-wilson committed Jan 10, 2024
1 parent a736dc3 commit 1c14508
Show file tree
Hide file tree
Showing 11 changed files with 165 additions and 370 deletions.
10 changes: 8 additions & 2 deletions .github/workflows/test_suite_python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,21 @@ jobs:
else
source .venv/bin/activate
fi
- name: Install dependencies
run: python -m pip install .[test]
- name: Lint with Ruff
run: |
python -m ruff --output-format=github .
- name: Lint with Black
run: |
python -m black --check .
- name: Build Rust
uses: PyO3/maturin-action@v1
with:
command: develop
sccache: 'true'
manylinux: auto
working-directory: bindings/python
- name: Install dependencies
run: python -m pip install .[test]
- name: Run tests
run: |
python -m pytest --hypothesis-profile default -n=auto tests/
2 changes: 2 additions & 0 deletions bindings/python/conftest.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# ruff: noqa: D100

import hypothesis

hypothesis.settings.register_profile("default", print_blob=True)
2 changes: 2 additions & 0 deletions bindings/python/docs/source/conf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# ruff: noqa: D100

# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
Expand Down
16 changes: 10 additions & 6 deletions bindings/python/pychecks.pyi
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Generic, TypeVar
import enum
from typing import TYPE_CHECKING, Generic, TypeVar

if TYPE_CHECKING:
from typing import Optional, List
from typing import List, Optional

T = TypeVar("T")

Expand All @@ -28,8 +28,12 @@ class Item(Generic[T]):
) -> None: ...
def __str__(self) -> str: ...
def __repr__(self) -> str: ...
def __eq__(self, other: T) -> bool: ...
def __lt__(self, other: T) -> bool: ...
def __eq__(self, other: Item[T]) -> bool: ...
def __ne__(self, other: Item[T]) -> bool: ...
def __lt__(self, other: Item[T]) -> bool: ...
def __le__(self, other: Item[T]) -> bool: ...
def __gt__(self, other: Item[T]) -> bool: ...
def __ge__(self, other: Item[T]) -> bool: ...
def value(self) -> T: ...
def type_hint(self) -> Optional[str]: ...

Expand Down Expand Up @@ -104,5 +108,5 @@ class CheckError(Exception): ...

def run(check: BaseCheck[T]) -> CheckResult[T]: ...
def auto_fix(check: BaseCheck[T]) -> CheckResult[T]: ...
async def async_run(check: BaseCheck[T]) -> CheckResult[T]: ...
async def async_auto_fix(check: BaseCheck[T]) -> CheckResult[T]: ...
async def async_run(check: AsyncBaseCheck[T]) -> CheckResult[T]: ...
async def async_auto_fix(check: AsyncBaseCheck[T]) -> CheckResult[T]: ...
49 changes: 45 additions & 4 deletions bindings/python/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,54 @@ dynamic = ["version"]
[project.optional-dependencies]
build = ["maturin ~= 1.4"]
test = [
"pytest ~= 7.4",
"pytest-xdist ~= 3.5",
"pytest-cov ~= 4.1",
"black ~= 23.12",
"hypothesis ~= 6.79",
"pytest ~= 7.4",
"pytest-asyncio ~= 0.21",
"pytest-cov ~= 4.1",
"pytest-xdist ~= 3.5",
"ruff ~= 0.1",
]
docs = ["sphinx ~= 5.3", "sphinx-rtd-theme ~= 2.0", "myst-parser ~= 1.0"]
docs = ["myst-parser ~= 1.0", "sphinx ~= 5.3", "sphinx-rtd-theme ~= 2.0"]

[tool.maturin]
features = ["pyo3/extension-module"]

[tool.ruff]
select = ["ANN", "BLE", "D", "E", "F", "I", "N", "PT", "S", "YTT"]
line-length = 88
ignore = ["ANN101", "ANN102"]

[tool.ruff.pydocstyle]
convention = "google"

[tool.mypy]
# Start off with these
warn_unused_configs = true
warn_redundant_casts = true
warn_unused_ignores = true
no_implicit_optional = true

# Getting these passing should be easy
strict_equality = true
strict_concatenate = true

# Strongly recommend enabling this one as soon as you can
check_untyped_defs = true

# These shouldn't be too much additional work, but may be tricky to
# get passing if you use a lot of untyped libraries
disallow_subclassing_any = true
disallow_untyped_decorators = true
disallow_any_generics = true

# These next few are various gradations of forcing use of type annotations
disallow_untyped_calls = true
disallow_incomplete_defs = true
disallow_untyped_defs = true

# This one isn't too hard to get passing, but return on investment is lower
no_implicit_reexport = true

# This one can be tricky to get passing if you use a lot of untyped libraries
warn_return_any = true
207 changes: 0 additions & 207 deletions bindings/python/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,210 +90,3 @@ impl Item {
}
}
}

// /// Item(value: T, type_hint: Optional[str] = None, debug_fn: Optional[Callable[[T], str]] = None, display_fn: Optional[Callable[[T], str]] = None, lt_fn: Optional[Callable[[T, T], bool]] = None, eq_fn: Optional[Callable[[T, T], bool]] = None)
// ///
// /// The item is a wrapper to make a result item more user interface friendly.
// ///
// /// Result items represent the objects that caused a result. For example, if a
// /// check failed because the bones in a character rig are not properly named,
// /// then the items would contain the bones that are named incorrectly.
// ///
// /// The item wrapper makes the use of items user interface friendly because it
// /// implements item sorting and a string representation of the item.
// ///
// /// Args:
// /// value (T): The wrapped value
// /// type_hint (Optional[str]): A hint to add extra context to the value.
// /// For example, if the value is a string, and that string represents a
// /// scene path, then a user interface could use that knowledge to select
// /// the scene path in the application. Default to the type having no
// /// meaning outside of itself.
// /// debug_fn (Optional[Callable[[T], str]]): The debug function for the
// /// item. Should be accessed via the :code:`repr(item)` function.
// /// Defaults to calling :code:`repr(value)`.
// /// display_fn (Optional[Callable[[T], str]]): The display function for the
// /// item. Should be accessed via the :code:`str(item)` function.
// /// Defaults to calling :code:`str(value)`.
// /// lt_fn (Optional[Callable[[T, T], bool]]): The less than function. Should
// /// be accessed by the :code:`item_a < item_b` operation. Defaults to
// /// calling :code:`value_a < value_b`.
// /// eq_fn (Optional[Callable[[T, T], bool]]): The equal function. Should be
// /// accessed by the :code:`item_a == item_b` operation. Defaults to
// /// calling :code:`value_a == value_b`.
// #[pyclass]
// #[derive(Debug, Clone)]
// pub(crate) struct Item {
// value: PyObject,
// type_hint: Option<Py<PyString>>,
// debug_fn: PyObject,
// display_fn: PyObject,
// lt_fn: PyObject,
// eq_fn: PyObject,
// }

// impl std::fmt::Display for Item {
// fn fmt(&self, _f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// unimplemented!()
// }
// }

// impl std::cmp::PartialEq for Item {
// fn eq(&self, _other: &Self) -> bool {
// unimplemented!()
// }
// }

// impl std::cmp::PartialOrd for Item {
// fn partial_cmp(&self, _other: &Self) -> Option<std::cmp::Ordering> {
// unimplemented!()
// }
// }

// impl checks::Item for Item {
// type Value = ();

// fn value(&self) -> Self::Value {
// unimplemented!()
// }
// }

// #[pymethods]
// impl Item {
// #[new]
// #[pyo3(signature = (
// value,
// type_hint = None,
// debug_fn = None,
// display_fn = None,
// lt_fn = None,
// eq_fn = None,
// ))]
// fn new(
// py: Python<'_>,
// value: PyObject,
// type_hint: Option<Py<PyString>>,
// debug_fn: Option<PyObject>,
// display_fn: Option<PyObject>,
// lt_fn: Option<PyObject>,
// eq_fn: Option<PyObject>,
// ) -> PyResult<Self> {
// let debug_fn = match debug_fn {
// Some(func) => func.extract::<PyObject>(py)?,
// None => py.eval("repr", None, None)?.extract::<PyObject>()?,
// };
// let display_fn = match display_fn {
// Some(func) => func.extract::<PyObject>(py)?,
// None => py.eval("str", None, None)?.extract::<PyObject>()?,
// };
// let lt_fn = match lt_fn {
// Some(func) => func.extract::<PyObject>(py)?,
// None => {
// if value.getattr(py, intern!(py, "__lt__")).is_err() {
// return Err(PyErr::new::<PyAttributeError, _>(
// "Value does not support ordering.",
// ));
// }

// let locals = PyDict::new(py);

// py.run("import operator; func = operator.lt", None, Some(locals))?;
// match locals.get_item("func")? {
// Some(func) => func.extract::<PyObject>()?,
// None => return Err(PyErr::new::<PyValueError, _>("Could not find function")),
// }
// .extract::<PyObject>(py)?
// }
// };
// let eq_fn = match eq_fn {
// Some(func) => func.extract::<PyObject>(py)?,
// None => {
// if value.getattr(py, intern!(py, "__eq__")).is_err() {
// return Err(PyErr::new::<PyAttributeError, _>(
// "Value does not support comparisons.",
// ));
// }

// let locals = PyDict::new(py);

// py.run("import operator; func = operator.eq", None, Some(locals))?;
// match locals.get_item("func")? {
// Some(func) => func.extract::<PyObject>()?,
// None => return Err(PyErr::new::<PyValueError, _>("Could not find function")),
// }
// .extract::<PyObject>(py)?
// }
// };

// Ok(Self {
// value,
// type_hint,
// debug_fn,
// display_fn,
// lt_fn,
// eq_fn,
// })
// }

// fn __repr__(&self, py: Python<'_>) -> PyResult<String> {
// Ok(format!(
// "Item({})",
// &self.debug_fn.call(py, (&self.value,), None)?
// ))
// }

// fn __str__(&self, py: Python<'_>) -> PyResult<String> {
// Ok(format!(
// "{}",
// self.display_fn.call(py, (&self.value,), None)?
// ))
// }

// fn __richcmp__(&self, py: Python<'_>, other: &Self, op: CompareOp) -> PyResult<bool> {
// let ordering = if self
// .lt_fn
// .call(py, (&self.value, &other.value), None)?
// .is_true(py)?
// {
// std::cmp::Ordering::Less
// } else if self
// .eq_fn
// .call(py, (&self.value, &other.value), None)?
// .is_true(py)?
// {
// std::cmp::Ordering::Equal
// } else {
// std::cmp::Ordering::Greater
// };

// Ok(op.matches(ordering))
// }

// /// value(self) -> T
// ///
// /// The value that is wrapped.
// ///
// /// Returns:
// /// T: The wrapped value.
// fn value(&self) -> &PyObject {
// &self.value
// }

// /// type_hint(self) -> Optional[str]
// ///
// /// A type hint can be used to add a hint to a system that the given type
// /// represents something else. For example, the value could be a string, but
// /// this is a scene path.
// ///
// /// A user interface could use this hint to select the item in the
// /// application.
// ///
// /// Returns:
// /// Optional[str]: The type hint.
// fn type_hint<'a>(&'a self, py: Python<'a>) -> Option<&'a PyString> {
// match &self.type_hint {
// Some(type_hint) => Some(type_hint.as_ref(py)),
// None => None,
// }
// }
// }
Loading

0 comments on commit 1c14508

Please sign in to comment.