From be04fdb849c6a92cd63cc8d54f6fd0ca66be4326 Mon Sep 17 00:00:00 2001 From: ARYAN-NIKNEZHAD Date: Fri, 30 Aug 2024 21:46:45 +0430 Subject: [PATCH] :wrench: chore: Update pre-commit config - Add pyproject.toml config hook - Add tox.ini config hook - Add pyupgrade hook - Add blacken docs hook for docs --- .pre-commit-config.yaml | 27 +++- docs/pytest_guide.rst | 43 ++++-- docs/quick_start.rst | 5 +- docs/usage.rst | 2 + pyproject.toml | 299 ++++++++++++++++++++-------------------- tests/constants.py | 1 - tox.ini | 45 +++--- 7 files changed, 235 insertions(+), 187 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d8b3b9..b95366b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,6 +2,9 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.3.0 hooks: + - id: check-toml + - id: check-yaml + files: \.yaml$ - id: trailing-whitespace exclude: (migrations/|tests/|docs/|static/|media/).* - id: end-of-file-fixer @@ -15,6 +18,21 @@ repos: - id: check-docstring-first exclude: (migrations/|tests/|docs/|static/|media/).* + - repo: https://github.com/tox-dev/pyproject-fmt + rev: 2.2.1 + hooks: + - id: pyproject-fmt + + - repo: https://github.com/tox-dev/tox-ini-fmt + rev: 1.3.1 + hooks: + - id: tox-ini-fmt + + - repo: https://github.com/asottile/pyupgrade + rev: v3.17.0 + hooks: + - id: pyupgrade + - repo: https://github.com/charliermarsh/ruff-pre-commit rev: v0.5.5 hooks: @@ -39,7 +57,6 @@ repos: rev: v3.28.0 hooks: - id: commitizen - exclude: (migrations/|tests/|docs/|static/|media/).* - repo: https://github.com/PyCQA/bandit rev: 1.7.4 @@ -56,6 +73,14 @@ repos: args: ["--in-place", "--recursive", "--blank"] exclude: (migrations/|tests/|docs/|static/|media/).* + - repo: https://github.com/adamchainz/blacken-docs + rev: 1.18.0 + hooks: + - id: blacken-docs + additional_dependencies: + - black==24.4.2 + files: '\.rst$' + - repo: https://github.com/rstcheck/rstcheck rev: "v6.2.4" hooks: diff --git a/docs/pytest_guide.rst b/docs/pytest_guide.rst index ed34f88..7be69e2 100644 --- a/docs/pytest_guide.rst +++ b/docs/pytest_guide.rst @@ -44,14 +44,17 @@ Example File Structure pytestmark = [ pytest.mark.django_db, pytest.mark.admin, - pytest.mark.skipif(sys.version_info < (3, 8), reason="Python 3.8 or higher required") + pytest.mark.skipif( + sys.version_info < (3, 8), reason="Python 3.8 or higher required" + ), ] User = get_user_model() + class TestMyModelAdmin: """Class for testing MyModelAdmin functionality.""" - + def test_some_functionality(self) -> None: # Test logic goes here pass @@ -76,7 +79,9 @@ Example of pytestmark pytestmark = [ pytest.mark.django_db, pytest.mark.admin, - pytest.mark.skipif(sys.version_info < (3, 8), reason="Python 3.8 or higher required") + pytest.mark.skipif( + sys.version_info < (3, 8), reason="Python 3.8 or higher required" + ), ] Docstrings @@ -149,14 +154,17 @@ Admin Model Test Example pytestmark = [ pytest.mark.django_db, pytest.mark.admin, - pytest.mark.skipif(sys.version_info < (3, 8), reason="Python 3.8 or higher required") + pytest.mark.skipif( + sys.version_info < (3, 8), reason="Python 3.8 or higher required" + ), ] User = get_user_model() + class TestMyModelAdmin: """Class for testing MyModelAdmin functionality.""" - + def test_formfield_for_foreignkey_sets_queryset(self) -> None: """ Test that the formfield for the ForeignKey correctly sets the queryset. @@ -165,12 +173,18 @@ Admin Model Test Example """ admin_site = AdminSite() request = HttpRequest() - request.user = User.objects.create_superuser('admin', 'admin@example.com', 'password') - + request.user = User.objects.create_superuser( + "admin", "admin@example.com", "password" + ) + model_admin = MyModelAdmin(model=MyModel, admin_site=admin_site) - db_field = MyModel._meta.get_field('related_model') - - with patch.object(MyModelAdmin, 'get_field_queryset', return_value=MyModel.objects.filter(name="Test")) as mock_get_field_queryset: + db_field = MyModel._meta.get_field("related_model") + + with patch.object( + MyModelAdmin, + "get_field_queryset", + return_value=MyModel.objects.filter(name="Test"), + ) as mock_get_field_queryset: formfield = model_admin.formfield_for_foreignkey(db_field, request) mock_get_field_queryset.assert_called_once_with(None, db_field, request) assert isinstance(formfield.widget, widgets.ForeignKeyRawIdWidget) @@ -189,12 +203,15 @@ Settings Check Test Example pytestmark = [ pytest.mark.settings_checks, - pytest.mark.skipif(sys.version_info < (3, 8), reason="Python 3.8 or higher required") + pytest.mark.skipif( + sys.version_info < (3, 8), reason="Python 3.8 or higher required" + ), ] + class TestMyAppConfig: """Test MyApp configuration and settings.""" - + def test_check_my_app_config_correct_settings(self, settings) -> None: """ Test the MyApp configuration checker with correct settings. @@ -204,7 +221,7 @@ Settings Check Test Example settings.MY_SETTING_ENABLED = True errors = check_my_app_config({}) assert len(errors) == 0 - + def test_check_my_app_config_invalid_type(self, settings) -> None: """ Test the MyApp configuration checker with invalid type settings. diff --git a/docs/quick_start.rst b/docs/quick_start.rst index 15b982d..989ee42 100644 --- a/docs/quick_start.rst +++ b/docs/quick_start.rst @@ -12,9 +12,8 @@ Quick Start .. code-block:: python INSTALLED_APPS = [ - ... - 'iranian_cities', - ... + ## Other apps + "iranian_cities", ] 3. **Run migrations to apply model changes**: diff --git a/docs/usage.rst b/docs/usage.rst index b24806f..6020ee0 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -10,6 +10,7 @@ You can use the provided fields and admin mixin in your Django models: from django.db import models from iranian_cities.fields import ProvinceField + class TestModel(models.Model): province = ProvinceField() @@ -29,6 +30,7 @@ You can use the provided fields and admin mixin in your Django models: from iranian_cities.admin import IranianCitiesAdmin from test_app.models import TestModel + @admin.register(TestModel) class TestModelAdmin(IranianCitiesAdmin): pass diff --git a/pyproject.toml b/pyproject.toml index 4d57bd6..82c072c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,13 +1,17 @@ +[build-system] +build-backend = "poetry.core.masonry.api" +requires = [ "poetry-core>=1" ] + [tool.poetry] name = "django-iranian-cities" version = "2.0.0" description = "Iranian cities support for Django" -authors = ["Sepehr Akbarzadeh "] +authors = [ "Sepehr Akbarzadeh " ] license = "GNU" -keywords = ["django", "iranian", "cities"] +keywords = [ "django", "iranian", "cities" ] repository = "https://github.com/sageteamorg/django-iranian-cities" packages = [ - {include = "iranian_cities"} + { include = "iranian_cities" }, ] [tool.poetry.urls] @@ -17,8 +21,8 @@ packages = [ [tool.poetry.dependencies] python = ">=3.8,<4.0" django = [ - { version = ">=4.2,<5.0", python = ">=3.8,<3.10"}, - { version = ">=4.2,<5.3", python = ">=3.10" } # Django 4.2 and 5.x for Python 3.10+ + { version = ">=4.2,<5.0", python = ">=3.8,<3.10" }, + { version = ">=4.2,<5.3", python = ">=3.10" }, # Django 4.2 and 5.x for Python 3.10+ ] [tool.poetry.dev-dependencies] @@ -38,93 +42,6 @@ pylint-django = "^2.5.5" docformatter = "^1.7.5" commitizen = "^3.28.0" - -[tool.pytest.ini_options] -addopts = "--cov --cov-report=term-missing --cov-report=html" -DJANGO_SETTINGS_MODULE = "kernel.settings" -python_files = ["tests.py", "test_*.py"] -testpaths = ["tests"] -markers = [ - "admin: mark test to check admin tests", - "models_str_method: mark test to check __str__ methods of models", - "models_code_field: mark test to check code fields in models", - "models_code_field_unique: mark test to check code fields are unique", - "settings_admin_permission: mark test to check admin permissions", - "settings_checks: mark test to check settings configuration", -] -norecursedirs = [ - "migrations", - "static", - "media", - "node_modules", - "env", - "venv", - ".venv", - "dist", - "build", - "kernel" -] - -[tool.coverage.run] -omit = [ - "*/migrations/*", - "kernel/*", - "*/apps.py", - "manage.py", -] - -[tool.coverage.report] -exclude_lines = [ - "pragma: no cover", - "def __repr__", - "if self\\.debug", - "raise AssertionError", - "if 0:", - "if __name__ == .__main__.:" -] - -[tool.ruff] -line-length = 88 -exclude = [ - "venv/*", - ".venv/*", - "build/*", - "dist/*", - ".git/*", - "__pycache__/*", - "*.egg-info/*", - ".mypy_cache/*", - ".pytest_cache/*", - "migrations/*" -] - -[tool.ruff.lint] -ignore = [ - "E203", # Ignore whitespace before ':', ';', or '#' - "E501", # Ignore line length issues (lines longer than 88 characters) - "F401" -] -select = [ - "E", # Select all PEP8 error codes - "W", # Select all warnings - "F", # Select all potential runtime errors - "C90" # Select custom or extended error code C90 -] - -[tool.mypy] -mypy_path = "stubs" -disallow_untyped_calls = true -disallow_untyped_defs = true -ignore_missing_imports = true -explicit_package_bases = true -exclude = ''' -^docs/source/conf.py| -^build/| -^tests/| -^stubs/| -^kernel/ -''' - [tool.black] line-length = 88 exclude = ''' @@ -148,77 +65,98 @@ exclude = ''' )/ ''' +[tool.ruff] +line-length = 88 +exclude = [ + "*.egg-info/*", + ".git/*", + ".mypy_cache/*", + ".pytest_cache/*", + ".venv/*", + "__pycache__/*", + "build/*", + "dist/*", + "migrations/*", + "venv/*", +] + +lint.select = [ + "C90", # Select custom or extended error code C90 + "E", # Select all PEP8 error codes + "F", # Select all potential runtime errors + "W", # Select all warnings +] +lint.ignore = [ + "E203", # Ignore whitespace before ':', ';', or '#' + "E501", # Ignore line length issues (lines longer than 88 characters) + "F401", +] + [tool.isort] profile = "black" line_length = 88 skip = [ - "venv", - ".venv", - "build", - "dist", - ".git", - "__pycache__", - "*.egg-info", - ".mypy_cache", - ".pytest_cache", - "migrations", - "static", - "media", - "node_modules", - "env", - "kernel" + "venv", + ".venv", + "build", + "dist", + ".git", + "__pycache__", + "*.egg-info", + ".mypy_cache", + ".pytest_cache", + "migrations", + "static", + "media", + "node_modules", + "env", + "kernel", ] -[tool.commitizen] -name = "cz_conventional_commits" -version = "0.1.0" - -[tool.commitizen.settings] -increment_types = ["feat", "fix"] - [tool.pylint] disable = [ - "C0103", # Invalid constant name - "C0114", # Missing module docstring - "C0115", # Missing class docstring - "C0116", # Missing function or method docstring - "E1101", # Instance of 'Foo' has no 'bar' member - "W0212", # Access to a protected member - "C0301", # Line too long - "C0411", # Wrong import order - "W0611", # Unused imports - "W0613", # Unused arguments - "W0622", # Redefining built-in names - "R0903", # Too few public methods - "R0801", # Duplicate code - "W0621", - "C0415", - "R1719", # The if expression can be replaced with 'bool(test)' - "R1705", # Unnecessary "elif" after "return" - "R0401", + "C0103", # Invalid constant name + "C0114", # Missing module docstring + "C0115", # Missing class docstring + "C0116", # Missing function or method docstring + "E1101", # Instance of 'Foo' has no 'bar' member + "W0212", # Access to a protected member + "C0301", # Line too long + "C0411", # Wrong import order + "W0611", # Unused imports + "W0613", # Unused arguments + "W0622", # Redefining built-in names + "R0903", # Too few public methods + "R0801", # Duplicate code + "W0621", + "C0415", + "R1719", # The if expression can be replaced with 'bool(test)' + "R1705", # Unnecessary "elif" after "return" + "R0401", + "W0223", ] max-line-length = 88 ignore = [ - "migrations/*", - "venv/*", - "build/*", - "dist/*", - ".git/*", - "__pycache__/*", - "*.egg-info/*", - ".mypy_cache/*", - ".pytest_cache/*" + "migrations/*", + "venv/*", + "build/*", + "dist/*", + ".git/*", + "__pycache__/*", + "*.egg-info/*", + ".mypy_cache/*", + ".pytest_cache/*", ] -django-settings-module= "kernel.settings" +django-settings-module = "kernel.settings" load-plugins = [ - "pylint_django", - "pylint.extensions.docparams", + "pylint_django", + "pylint.extensions.docparams", ] good-names = [ - "qs", # QuerySet abbreviation - "pk", # Primary key abbreviation - "id", # Identifier + "qs", # QuerySet abbreviation + "pk", # Primary key abbreviation + "id", # Identifier ] suggestion-mode = true const-rgx = "([A-Z_][A-Z0-9_]*)|(__.*__)" @@ -230,6 +168,67 @@ function-rgx = "[a-z_][a-z0-9_]{2,30}$" class-rgx = "[A-Z_][a-zA-Z0-9]+$" module-rgx = "(([a-z_][a-z0-9_]*)|(__.*__))$" -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" +[tool.pytest.ini_options] +addopts = "--cov --cov-report=term-missing --cov-report=html" +DJANGO_SETTINGS_MODULE = "kernel.settings" +python_files = [ "tests.py", "test_*.py" ] +testpaths = [ "tests" ] +markers = [ + "admin: mark test to check admin tests", + "models_str_method: mark test to check __str__ methods of models", + "models_code_field: mark test to check code fields in models", + "models_code_field_unique: mark test to check code fields are unique", + "settings_admin_permission: mark test to check admin permissions", + "settings_checks: mark test to check settings configuration", +] +norecursedirs = [ + "migrations", + "static", + "media", + "node_modules", + "env", + "venv", + ".venv", + "dist", + "build", + "kernel", +] + +[tool.coverage.run] +omit = [ + "*/migrations/*", + "kernel/*", + "*/apps.py", + "manage.py", +] + +[tool.coverage.report] +exclude_lines = [ + "pragma: no cover", + "def __repr__", + "if self\\.debug", + "raise AssertionError", + "if 0:", + "if __name__ == .__main__.:", +] + +[tool.mypy] +mypy_path = "stubs" +disallow_untyped_calls = true +disallow_untyped_defs = true +ignore_missing_imports = true +explicit_package_bases = true +exclude = ''' +^docs/source/conf.py| +^build/| +^tests/| +^stubs/| +^kernel/ +''' + +[tool.commitizen] +name = "cz_conventional_commits" +version = "0.1.0" + +[tool.commitizen.settings] +increment_types = [ "feat", "fix" ] diff --git a/tests/constants.py b/tests/constants.py index 561af74..b48b8b0 100644 --- a/tests/constants.py +++ b/tests/constants.py @@ -1,4 +1,3 @@ - PYTHON_VERSION = (3, 8) PYTHON_VERSION_REASON = "Requires Python 3.8 or higher" diff --git a/tox.ini b/tox.ini index f444f96..e834078 100644 --- a/tox.ini +++ b/tox.ini @@ -1,35 +1,42 @@ [tox] -envlist = - py38-django40, py39-django40, py310-django40, py311-django40, py312-django40, - py310-django50, py311-django50, py312-django50 - -[gh-actions] -python = - 3.8: py38 - 3.9: py39 - 3.10: py310 - 3.11: py311 - 3.12: py312 +requires = + tox>=4.2 +env_list = + py312-django40 + py312-django50 + py311-django40 + py311-django50 + py310-django40 + py310-django50 + py39-django40 + py38-django40 [testenv] description = Run Pytest tests with multiple django versions -usedevelop = True +package = editable deps = - django40: django>=4.2,<5.0 - django50: django>=5.0,<5.3 + django-stubs pytest - pytest-django pytest-cov - django-stubs + pytest-django + django40: django<5.0,>=4.2 + django50: django<5.3,>=5 +set_env = + DJANGO_SETTINGS_MODULE = kernel.settings commands = pytest --cov -setenv = - DJANGO_SETTINGS_MODULE = kernel.settings - [testenv:pre-commit] description = Run pre-commit hooks deps = pre-commit commands = pre-commit run --all-files + +[gh-actions] +python = + 3.8: py38 + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312