From 0cf3901017778da302191713135a67843bbc9df6 Mon Sep 17 00:00:00 2001 From: David Danier Date: Thu, 10 Aug 2023 18:33:14 +0200 Subject: [PATCH] =?UTF-8?q?build:=20=F0=9F=9B=A0=20Convert=20everything=20?= =?UTF-8?q?to=20use=20ruff=20and=20just?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .flake8 | 29 --------- .../workflows/{flake8-mypy.yml => lint.yml} | 4 +- .pre-commit-config.yaml | 29 ++------- build/Taskfile | 60 ------------------- justfile | 30 ++++++++++ pydantic_changedetect/_compat.py | 2 +- pydantic_changedetect/changedetect.py | 11 +++- pydantic_changedetect/utils.py | 1 + pyproject.toml | 25 ++++---- tests/test_changedetect.py | 18 +++--- 10 files changed, 69 insertions(+), 140 deletions(-) delete mode 100644 .flake8 rename .github/workflows/{flake8-mypy.yml => lint.yml} (82%) delete mode 100644 build/Taskfile create mode 100644 justfile diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 87b77c6..0000000 --- a/.flake8 +++ /dev/null @@ -1,29 +0,0 @@ -[flake8] -exclude = - *.egg-info, - .git, - .mypy_cache - .nox, - .pytest_cache, - __pycache__, -# * A001 variable is shadowing a python builtin -> we need to have "id", "filter", ... -# * A002 argument is shadowing a python builtin -> we need to have "id", "filter", ... -# * ANN101 Missing type annotation for self in method -# * ANN102 Missing type annotation for cls in class method -# * ANN401 Disallow typing.Any -> We want to use this -# * W503 line break before binary operator -# * B008 function calls for default values - this is used heavily by pydantic/fastapi -ignore = A001,A002,A003,ANN101,ANN102,ANN401,B305,C901,E704,N8,W503,B008,F405,F821 - -# * commands allow print statements (T201) -# * Allow undefined names in migrations (F821) -# * Allow unused imports in __init__.py (F401) -# * No annotations in tests and fixtures required (ANN) -# * Special treatment for test fixtures and tests (F811) -per-file-ignores = - __init__.py: F401 - *_fixture.py: E501,ANN,F811 - test_*.py: E501,ANN,F811,F401 - conftest.py: E501,ANN,F811 -max-complexity = 5 -max-line-length = 115 diff --git a/.github/workflows/flake8-mypy.yml b/.github/workflows/lint.yml similarity index 82% rename from .github/workflows/flake8-mypy.yml rename to .github/workflows/lint.yml index dc1bf9f..d89962d 100644 --- a/.github/workflows/flake8-mypy.yml +++ b/.github/workflows/lint.yml @@ -13,7 +13,7 @@ jobs: run: | python -m pip install --upgrade poetry poetry install - - name: Lint with flake8 + - name: Lint with ruff & mypy run: | - poetry run flake8 pydantic_changedetect tests + poetry run ruff check pydantic_changedetect tests poetry run mypy pydantic_changedetect diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ce5a8db..b9b0dd9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,32 +7,11 @@ repos: - id: check-merge-conflict - id: check-docstring-first - id: debug-statements - - repo: https://github.com/PyCQA/flake8 - rev: 6.0.0 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.0.284 hooks: - - id: flake8 - args: ["--config=.flake8"] - additional_dependencies: - - flake8-builtins - - flake8-annotations - - flake8-commas - - flake8-isort - - flake8-print - - flake8-debugger - - repo: https://github.com/pycqa/isort - rev: 5.12.0 - hooks: - - id: isort - - repo: https://github.com/asottile/pyupgrade - rev: v3.9.0 - hooks: - - id: pyupgrade - args: ["--py37-plus"] - - repo: https://github.com/asottile/add-trailing-comma - rev: v3.0.0 - hooks: - - id: add-trailing-comma - args: ["--py36-plus"] + - id: ruff + args: [--fix, --exit-non-zero-on-fix] - repo: https://github.com/Lucas-C/pre-commit-hooks-safety rev: v1.3.1 hooks: diff --git a/build/Taskfile b/build/Taskfile deleted file mode 100644 index dc14656..0000000 --- a/build/Taskfile +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env bash -# b5 Taskfile, see https://git.team23.de/build/b5 for details - -pre-commit:install() { - if ( which pre-commit > /dev/null 2>&1 ) - then - pre-commit install --install-hooks - else - b5:warn "-----------------------------------------------------------------" - b5:warn "pre-commit is not installed - cannot enable pre-commit hooks!" - b5:warn "Recommendation: Install pre-commit ('brew install pre-commit')." - b5:warn "-----------------------------------------------------------------" - fi -} - -task:install() { - task:poetry install - - pre-commit:install -} - -task:update() { - task:poetry install -} - -task:poetry() { - ( - cd .. && \ - poetry "$@" - ) -} - -task:test() { - task:poetry run pytest --cov=pydantic_changedetect --cov-report term-missing:skip-covered "$@" -} - -task:test:all() { - task:poetry run tox -} - -task:isort() { - task:poetry run isort pydantic_changedetect tests -} - -task:flake8() { - task:poetry run flake8 pydantic_changedetect tests -} - -task:mypy() { - task:poetry run mypy pydantic_changedetect -} - -task:lint() { - task:flake8 - task:mypy -} - -task:publish() { - task:poetry publish --build -} diff --git a/justfile b/justfile new file mode 100644 index 0000000..e0fca82 --- /dev/null +++ b/justfile @@ -0,0 +1,30 @@ +install-pre-commit: + #!/usr/bin/env bash + if ( which pre-commit > /dev/null 2>&1 ) + then + pre-commit install --install-hooks + else + echo "-----------------------------------------------------------------" + echo "pre-commit is not installed - cannot enable pre-commit hooks!" + echo "Recommendation: Install pre-commit ('brew install pre-commit')." + echo "-----------------------------------------------------------------" + fi + +install: install-pre-commit (poetry "install") + +update: (poetry "install") + +poetry *args: + poetry {{args}} + +test *args: (poetry "run" "pytest" "--cov=pydantic_changedetect" "--cov-report" "term-missing:skip-covered" args) + +test-all: (poetry "run" "tox") + +ruff *args: (poetry "run" "ruff" "check" "pydantic_changedetect" "tests" args) + +mypy *args: (poetry "run" "mypy" "pydantic_changedetect" args) + +lint: ruff mypy + +publish: (poetry "publish" "--build") diff --git a/pydantic_changedetect/_compat.py b/pydantic_changedetect/_compat.py index 7ee12e1..7db6ea4 100644 --- a/pydantic_changedetect/_compat.py +++ b/pydantic_changedetect/_compat.py @@ -8,7 +8,7 @@ PYDANTIC_V2 = PYDANTIC_VERSION.startswith("2.") if PYDANTIC_V1: # pragma: no cover - class PydanticCompat: # noqa: F811 + class PydanticCompat: obj: pydantic.BaseModel def __init__( diff --git a/pydantic_changedetect/changedetect.py b/pydantic_changedetect/changedetect.py index 17e46f2..e8f1e3d 100644 --- a/pydantic_changedetect/changedetect.py +++ b/pydantic_changedetect/changedetect.py @@ -354,6 +354,7 @@ def model_dump_json( return super().model_dump_json( **self._get_changed_export_includes( + indent=indent, include=include, exclude=exclude, by_alias=by_alias, @@ -373,12 +374,13 @@ def copy( *, include: "Union[AbstractSetIntStr, MappingIntStrAny, None]" = None, exclude: "Union[AbstractSetIntStr, MappingIntStrAny, None]" = None, - update: Optional[Dict[str, Any]] = None, # noqa UP006 + update: Optional[Dict[str, Any]] = None, deep: bool = False, ) -> "Model": warnings.warn( "copy(...) is deprecated even in pydantic v2, use model_copy(...) instead", DeprecationWarning, + stacklevel=2, ) clone = cast( "Model", @@ -559,6 +561,7 @@ def reset_changed(self) -> None: warnings.warn( "reset_changed() is deprecated, use model_reset_changed() instead", DeprecationWarning, + stacklevel=2, ) self.model_reset_changed() @@ -567,6 +570,7 @@ def __original__(self) -> Dict[str, Any]: warnings.warn( "__original__ is deprecated, use model_original instead", DeprecationWarning, + stacklevel=2, ) return self.model_original @@ -575,6 +579,7 @@ def __self_changed_fields__(self) -> Set[str]: warnings.warn( "__self_changed_fields__ is deprecated, use model_self_changed_fields instead", DeprecationWarning, + stacklevel=2, ) return self.model_self_changed_fields @@ -583,6 +588,7 @@ def __changed_fields__(self) -> Set[str]: warnings.warn( "__changed_fields__ is deprecated, use model_changed_fields instead", DeprecationWarning, + stacklevel=2, ) return self.model_changed_fields @@ -591,6 +597,7 @@ def __changed_fields_recursive__(self) -> Set[str]: warnings.warn( "__changed_fields_recursive__ is deprecated, use model_changed_fields_recursive instead", DeprecationWarning, + stacklevel=2, ) return self.model_changed_fields_recursive @@ -599,6 +606,7 @@ def has_changed(self) -> bool: warnings.warn( "has_changed is deprecated, use model_has_changed instead", DeprecationWarning, + stacklevel=2, ) return self.model_has_changed @@ -612,5 +620,6 @@ def set_changed(self, *fields: str, original: Any = NO_VALUE) -> None: warnings.warn( "set_changed(...) is deprecated, use model_set_changed(...) instead", DeprecationWarning, + stacklevel=2, ) self.model_set_changed(*fields, original=original) diff --git a/pydantic_changedetect/utils.py b/pydantic_changedetect/utils.py index 1042f4f..4d6b86f 100644 --- a/pydantic_changedetect/utils.py +++ b/pydantic_changedetect/utils.py @@ -26,6 +26,7 @@ def safe_issubclass(cls: Any, type_: Any) -> bool: warnings.warn( "safe_issubclass() is deprecated and will be removed", DeprecationWarning, + stacklevel=2, ) if not isinstance(cls, type): diff --git a/pyproject.toml b/pyproject.toml index d4b8a67..e14b584 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -13,22 +13,21 @@ pydantic = ">=1.9.0,<3.0.0" [tool.poetry.group.dev.dependencies] pytest = ">=7.1.2,<8.0.0" -isort = "^5.10.1" -mypy = ">=0.971,<2.0" -flake8 = ">=5.0.4,<7.0.0" -flake8-builtins = ">=1.5.3,<3.0.0" -flake8-annotations = ">=2.9.1,<4.0.0" -flake8-commas = "^2.1.0" -flake8-isort = ">=4.2,<7.0" -flake8-print = "^5.0.0" -flake8-debugger = "^4.1.2" pytest-cov = ">=3,<5" +mypy = ">=0.971,<2.0" tox = ">=3.26,<5.0" +ruff = "^0.0.284" + +[tool.ruff] +select = ["F","E","W","C","I","N","UP","ANN","S","B","A","COM","C4","T20","PT","ARG","TD","RUF"] +line-length = 115 +target-version = "py38" +ignore = ["A001","A002","A003","ANN101","ANN102","ANN401","C901","N8","B008","F405","F821"] -[tool.isort] -multi_line_output = 3 -include_trailing_comma = true -line_length = 115 +[tool.ruff.per-file-ignores] +"__init__.py" = ["F401"] +"conftest.py" = ["S101","ANN","F401"] +"test_*.py" = ["S101","ANN","F401"] [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/tests/test_changedetect.py b/tests/test_changedetect.py index 9bb6b44..54329bc 100644 --- a/tests/test_changedetect.py +++ b/tests/test_changedetect.py @@ -282,13 +282,13 @@ def test_changed_base_is_resetable_with_v1_api(): def test_pickle_keeps_state(): obj = Something(id=1) - assert not pickle.loads(pickle.dumps(obj)).model_has_changed - assert pickle.loads(pickle.dumps(obj)).model_changed_fields == set() + assert not pickle.loads(pickle.dumps(obj)).model_has_changed # noqa: S301 + assert pickle.loads(pickle.dumps(obj)).model_changed_fields == set() # noqa: S301 obj.id = 2 - assert pickle.loads(pickle.dumps(obj)).model_has_changed - assert pickle.loads(pickle.dumps(obj)).model_changed_fields == {"id"} + assert pickle.loads(pickle.dumps(obj)).model_has_changed # noqa: S301 + assert pickle.loads(pickle.dumps(obj)).model_changed_fields == {"id"} # noqa: S301 def test_pickle_even_works_when_changed_state_is_missing(): @@ -296,8 +296,8 @@ def test_pickle_even_works_when_changed_state_is_missing(): obj.id = 2 # Now we cannot use the changed state, but nothing fails - assert not pickle.loads(pickle.dumps(obj)).model_has_changed - assert pickle.loads(pickle.dumps(obj)).model_changed_fields == set() + assert not pickle.loads(pickle.dumps(obj)).model_has_changed # noqa: S301 + assert pickle.loads(pickle.dumps(obj)).model_changed_fields == set() # noqa: S301 def test_stores_original(): @@ -330,7 +330,7 @@ def test_nested_changed_state(): @pytest.mark.parametrize( - "parent_class, list_type", [ + ("parent_class", "list_type"), [ (NestedList, list), (NestedTuple, tuple), ], @@ -409,7 +409,7 @@ def test_model_construct_works(): @pytest.mark.skipif(PYDANTIC_V1, reason="pydantic v1 does not trigger warnings") -def test_construct_works(): +def test_construct_works_on_v2(): with pytest.warns(DeprecationWarning): something = Something.construct(id=1) @@ -421,7 +421,7 @@ def test_construct_works(): @pytest.mark.skipif(PYDANTIC_V2, reason="pydantic v2 does trigger warnings") -def test_construct_works(): +def test_construct_works_on_v1(): something = Something.construct(id=1) assert something.model_has_changed is False