diff --git a/.flake8 b/.flake8 deleted file mode 100644 index 1abb1ca..0000000 --- a/.flake8 +++ /dev/null @@ -1,38 +0,0 @@ -[flake8] -max-line-length = 88 -max-complexity = 8 -# http://flake8.pycqa.org/en/2.5.5/warnings.html#warning-error-codes -ignore = - # pydocstyle - docstring conventions (PEP257) - D100 # Missing docstring in public module - D101 # Missing docstring in public class - D102 # Missing docstring in public method - D103 # Missing docstring in public function - D104 # Missing docstring in public package - D105 # Missing docstring in magic method - D106 # Missing docstring in public nested class - D107 # Missing docstring in __init__ - D412 # No blank lines allowed between a section header and its content - # pycodestyle - style checker (PEP8) - W503 # line break before binary operator - # the following are ignored in CI using --extend-ignore option: - ; D205 # [pydocstyle] 1 blank line required between summary line and description - ; D400 # [pydocstyle] First line should end with a period - ; D401 # [pydocstyle] First line should be in imperative mood - ; S308 # [bandit] Use of mark_safe() may expose cross-site scripting vulnerabilities and should be reviewed. - ; S703 # [bandit] Potential XSS on mark_safe function. - -per-file-ignores = - ; D205 - 1 blank line required between summary line and description - ; D400 - First line should end with a period - ; D401 - First line should be in imperative mood - ; S101 - use of assert - ; S106 - hard-coded password - ; E501 - line-length - ; E731 - assigning a lambda to a variable - *tests/*:D205,D400,D401,S101,S106,E501,E731 - */migrations/*:E501 - ; F403 - unable to detect undefined names - ; F405 - may be undefined, or defined from star imports - */settings.py:F403,F405 - */settings/*:F403,F405 diff --git a/.github/workflows/tox.yml b/.github/workflows/tox.yml index 4dba7f7..49c22d4 100644 --- a/.github/workflows/tox.yml +++ b/.github/workflows/tox.yml @@ -1,58 +1,93 @@ name: Python / Django on: - push: - branches: - - master + push: + branches: + - master - pull_request: - types: [opened, synchronize, reopened] + pull_request: + types: [opened, synchronize, reopened] jobs: - format: - name: Check formatting - runs-on: ubuntu-latest - strategy: - matrix: - toxenv: [fmt, lint, mypy] - env: - TOXENV: ${{ matrix.toxenv }} - - steps: - - name: Check out the repository - uses: actions/checkout@v3 - - - name: Set up Python 3.11 - uses: actions/setup-python@v4 - with: - python-version: "3.11" - - - name: Install and run tox - run: | - pip install tox - tox - - test: - name: Run tests - runs-on: ubuntu-latest - strategy: - matrix: - python: ["3.9", "3.10", "3.11"] - django: [32,41,main] - - env: - TOXENV: py${{ matrix.python }}-django${{ matrix.django }} - - steps: - - name: Check out the repository - uses: actions/checkout@v3 - - - name: Set up Python ${{ matrix.python }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - - name: Install and run tox - run: | - pip install tox - tox + format: + name: Check formatting + runs-on: ubuntu-latest + strategy: + matrix: + toxenv: [fmt, lint, mypy] + env: + TOXENV: ${{ matrix.toxenv }} + + steps: + - name: Check out the repository + uses: actions/checkout@v4 + + - name: Set up Python (3.11) + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Install and run tox + run: | + pip install tox + tox + + checks: + name: Run Django checks + runs-on: ubuntu-latest + strategy: + matrix: + toxenv: ["django-checks"] + env: + TOXENV: ${{ matrix.toxenv }} + + steps: + - name: Check out the repository + uses: actions/checkout@v4 + + - name: Set up Python (3.11) + uses: actions/setup-python@v4 + with: + python-version: "3.11" + + - name: Install and run tox + run: | + pip install tox + tox + + test: + name: Run tests + runs-on: ubuntu-latest + strategy: + matrix: + python: ["3.9", "3.10", "3.11", "3.12"] + # build LTS version, next version, HEAD + django: ["32", "42", "50", "main"] + exclude: + - python: "3.9" + django: "50" + - python: "3.9" + django: "main" + - python: "3.10" + django: "main" + - python: "3.11" + django: "32" + - python: "3.12" + django: "32" + + env: + TOXENV: django${{ matrix.django }}-py${{ matrix.python }} + + steps: + - name: Check out the repository + uses: actions/checkout@v4 + + - name: Set up Python ${{ matrix.python }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python }} + + - name: Install and run tox + run: | + pip install tox + tox diff --git a/.isort.cfg b/.isort.cfg deleted file mode 100644 index 629cb68..0000000 --- a/.isort.cfg +++ /dev/null @@ -1,8 +0,0 @@ -[settings] -default_section=THIRDPARTY -indent=' ' -sections=FUTURE,STDLIB,THIRDPARTY,FIRSTPARTY,LOCALFOLDER -multi_line_output=3 -line_length=88 -include_trailing_comma=True -use_parentheses=True diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 85452d8..def9258 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,39 +1,22 @@ repos: - # python import sorting - will amend files - - repo: https://github.com/pre-commit/mirrors-isort - rev: v5.10.1 - hooks: - - id: isort - # python code formatting - will amend files - repo: https://github.com/ambv/black - rev: 22.10.0 + rev: 23.10.1 hooks: - id: black - - repo: https://github.com/asottile/pyupgrade - rev: v3.2.0 - hooks: - - id: pyupgrade - - # Flake8 includes pyflakes, pycodestyle, mccabe, pydocstyle, bandit - - repo: https://gitlab.com/pycqa/flake8 - rev: 3.9.2 + - repo: https://github.com/charliermarsh/ruff-pre-commit + # Ruff version. + rev: "v0.1.5" hooks: - - id: flake8 - additional_dependencies: - - flake8-bandit - - flake8-blind-except - - flake8-docstrings - - flake8-logging-format - - flake8-print + - id: ruff + args: [--fix, --exit-non-zero-on-fix] # python static type checking - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.990 + rev: v1.7.0 hooks: - id: mypy - # additional_dependencies: args: - --disallow-untyped-defs - --disallow-incomplete-defs @@ -41,4 +24,3 @@ repos: - --no-implicit-optional - --ignore-missing-imports - --follow-imports=silent - exclude: ^tests diff --git a/CHANGELOG b/CHANGELOG index 88a6237..5029e10 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,7 +2,13 @@ All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). +## v1.1 + +- Added support for Django 5.0 +- Added support for Python 3.12 +- Replaced flake8, isort with ruff + +No code changes. ## v1.0 diff --git a/LICENSE b/LICENSE index 055cadf..13a245a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT Licence (MIT) -Copyright (c) 2022 YunoJuno Ltd +Copyright (c) 2023 YunoJuno Limited Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/pyproject.toml b/pyproject.toml index 5246330..20e2829 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "django-request-profiler" -version = "1.0" +version = "1.1" description = "A simple Django project profiler for timing HTTP requests." authors = ["YunoJuno "] license = "MIT" @@ -16,10 +16,12 @@ classifiers = [ "Framework :: Django :: 3.2", "Framework :: Django :: 4.0", "Framework :: Django :: 4.1", + "Framework :: Django :: 5.0", "Programming Language :: Python :: 3 :: Only", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] packages = [ { include = "request_profiler" } @@ -27,24 +29,17 @@ packages = [ [tool.poetry.dependencies] python = "^3.9" -django = "^3.2 || ^4.0" +django = "^3.2 || ^4.0 || ^5.0" [tool.poetry.dev-dependencies] black = "*" coverage = "*" -flake8 = "*" -flake8-bandit = "*" -flake8-blind-except = "*" -flake8-docstrings = "*" -flake8-logging-format = "*" -flake8-print = "*" -freezegun = "*" -isort = "*" mypy = "*" pre-commit = "*" pytest = "*" pytest-cov = "*" pytest-django = "*" +ruff = "*" tox = "*" [build-system] diff --git a/request_profiler/admin.py b/request_profiler/admin.py index 5571fb1..02333d1 100644 --- a/request_profiler/admin.py +++ b/request_profiler/admin.py @@ -4,12 +4,10 @@ class RuleSetAdmin(admin.ModelAdmin): - list_display = ("enabled", "uri_regex", "user_filter_type", "user_group_filter") class ProfilingRecordAdmin(admin.ModelAdmin): - list_display = ( "start_ts", "user", diff --git a/request_profiler/apps.py b/request_profiler/apps.py index f291f05..5b550a3 100644 --- a/request_profiler/apps.py +++ b/request_profiler/apps.py @@ -2,7 +2,6 @@ class RequestProfilerAppConfig(AppConfig): - name = "request_profiler" verbose_name = "Request Profiler" default_auto_field = "django.db.models.BigAutoField" diff --git a/request_profiler/management/commands/truncate_request_profiler_logs.py b/request_profiler/management/commands/truncate_request_profiler_logs.py index 0d020b0..073880d 100644 --- a/request_profiler/management/commands/truncate_request_profiler_logs.py +++ b/request_profiler/management/commands/truncate_request_profiler_logs.py @@ -10,7 +10,6 @@ class Command(BaseCommand): - help = "Truncate the profiler log after a specified number days." def add_arguments(self, parser: CommandParser) -> None: diff --git a/request_profiler/migrations/0001_initial.py b/request_profiler/migrations/0001_initial.py index 7f2406f..3f4ef10 100644 --- a/request_profiler/migrations/0001_initial.py +++ b/request_profiler/migrations/0001_initial.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [migrations.swappable_dependency(settings.AUTH_USER_MODEL)] operations = [ diff --git a/request_profiler/migrations/0002_profilingrecord_http_referer.py b/request_profiler/migrations/0002_profilingrecord_http_referer.py index 3abf77d..1fa90fa 100644 --- a/request_profiler/migrations/0002_profilingrecord_http_referer.py +++ b/request_profiler/migrations/0002_profilingrecord_http_referer.py @@ -5,7 +5,6 @@ class Migration(migrations.Migration): - dependencies = [("request_profiler", "0001_initial")] operations = [ diff --git a/request_profiler/migrations/0003_profilingrecord_query_string.py b/request_profiler/migrations/0003_profilingrecord_query_string.py index 7a3ab17..41aa706 100644 --- a/request_profiler/migrations/0003_profilingrecord_query_string.py +++ b/request_profiler/migrations/0003_profilingrecord_query_string.py @@ -6,7 +6,6 @@ class Migration(migrations.Migration): - dependencies = [("request_profiler", "0002_profilingrecord_http_referer")] operations = [ diff --git a/request_profiler/migrations/0004_profilingrecord_query_count.py b/request_profiler/migrations/0004_profilingrecord_query_count.py index e3d1fdb..74f1ea3 100644 --- a/request_profiler/migrations/0004_profilingrecord_query_count.py +++ b/request_profiler/migrations/0004_profilingrecord_query_count.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [("request_profiler", "0003_profilingrecord_query_string")] operations = [ diff --git a/request_profiler/migrations/0005_alter_profilingrecord_id_alter_ruleset_id.py b/request_profiler/migrations/0005_alter_profilingrecord_id_alter_ruleset_id.py index 8c20b90..c0d7e88 100644 --- a/request_profiler/migrations/0005_alter_profilingrecord_id_alter_ruleset_id.py +++ b/request_profiler/migrations/0005_alter_profilingrecord_id_alter_ruleset_id.py @@ -4,7 +4,6 @@ class Migration(migrations.Migration): - dependencies = [ ("request_profiler", "0004_profilingrecord_query_count"), ] diff --git a/tests/models.py b/tests/models.py index 982d514..bd10c56 100644 --- a/tests/models.py +++ b/tests/models.py @@ -5,7 +5,6 @@ class CustomUserManager(BaseUserManager): - # override this method def _create_user( self, diff --git a/tests/settings.py b/tests/settings.py index 42a1fe1..11ba8ac 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -5,6 +5,8 @@ DATABASES = {"default": {"ENGINE": "django.db.backends.sqlite3", "NAME": "test.db"}} +DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + INSTALLED_APPS = ( "django.contrib.admin", "django.contrib.auth", diff --git a/tests/test_middleware.py b/tests/test_middleware.py index 6740216..ba85094 100644 --- a/tests/test_middleware.py +++ b/tests/test_middleware.py @@ -104,7 +104,6 @@ def test_process_view__as_callable_object(self): self.assertEqual(request.profiler.view_func_name, "DummyView") def test_process_response(self): - request = self.factory.get("/") middleware = ProfilingMiddleware(get_response=lambda r: None) with self.assertRaises(ValueError): @@ -126,7 +125,6 @@ def test_process_response(self): self.assertTrue(response["X-Profiler-Duration"], request.profiler.duration) def test_process_response_signal_cancellation(self): - request = self.factory.get("/") request.profiler = ProfilingRecord().start() middleware = ProfilingMiddleware(get_response=lambda r: None) @@ -150,7 +148,6 @@ def on_request_profile_complete(sender, **kwargs): self.assertIsNone(request.profiler.id) def test_global_exclude_function(self): - # set the func to ignore everything RuleSet().save() request = self.factory.get("/") @@ -235,7 +232,6 @@ def test_process_view__as_callable_object(self): self.assertEqual(request.profiler.view_func_name, "DummyView") def test_process_response(self): - request = self.factory.get("/") middleware = ProfilingMiddleware(get_response=lambda r: None) with self.assertRaises(AssertionError): @@ -257,7 +253,6 @@ def test_process_response(self): self.assertTrue(response["X-Profiler-Duration"], request.profiler.duration) def test_process_response_signal_cancellation(self): - request = self.factory.get("/") request.profiler = ProfilingRecord().start() middleware = ProfilingMiddleware(get_response=lambda r: None) @@ -281,7 +276,6 @@ def on_request_profile_complete(sender, **kwargs): self.assertIsNone(request.profiler.id) def test_global_exclude_function(self): - # set the func to ignore everything RuleSet().save() request = self.factory.get("/") diff --git a/tests/test_models.py b/tests/test_models.py index 5a49586..015bce5 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -37,7 +37,6 @@ class RuleSetQuerySetTests(TestCase): """Basic model manager method tests.""" def test_live_rules(self): - _ = RuleSet.objects.create(uri_regex="", enabled=True) self.assertEqual(RuleSet.objects.live_rules().count(), 1) @@ -50,7 +49,6 @@ def test_live_rules(self): self.assertEqual(RuleSet.objects.live_rules().count(), 1) def test_live_rules_with_caching(self): - settings.RULESET_CACHE_TIMEOUT = 10 self.assertIsNone(cache.get(settings.RULESET_CACHE_KEY)) # save a couple of rules @@ -325,7 +323,6 @@ def test_elapsed(self): @skipIfCustomUser def test_process_request(self): - factory = RequestFactory() request = factory.get("/test") request.META["HTTP_USER_AGENT"] = "test-browser" @@ -362,7 +359,6 @@ def test_process_request(self): @skipIfDefaultUser def test_process_request_with_custom_user(self): - factory = RequestFactory() request = factory.get("/test") request.META["HTTP_USER_AGENT"] = "test-browser" diff --git a/tox.ini b/tox.ini index bda4a95..b93f266 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,15 @@ [tox] isolated_build = True -envlist = fmt, lint, mypy, py{3.9,3.10,3.11}-django{32,40,41,main} +envlist = + fmt, lint, mypy, + django-checks, + ; https://docs.djangoproject.com/en/5.0/releases/ + django32-py{39,310} + django40-py{39,310} + django41-py{39,310,311} + django42-py{39,310,311} + django50-py{310,311,312} + djangomain-py{311,312} [testenv] deps = @@ -11,33 +20,38 @@ deps = django32: Django>=3.2,<3.3 django40: Django>=4.0,<4.1 django41: Django>=4.1,<4.2 - djangomaster: https://github.com/django/django/archive/main.tar.gz + django42: Django>=4.2,<4.3 + django50: https://github.com/django/django/archive/stable/5.0.x.tar.gz + djangomain: https://github.com/django/django/archive/main.tar.gz commands = - pytest --verbose tests + pytest --cov=request_profiler --verbose tests/ + +[testenv:django-checks] +description = Django system checks and missing migrations +deps = Django +commands = + python manage.py check --fail-level WARNING + python manage.py makemigrations --dry-run --check --verbosity 3 [testenv:fmt] +description = Python source code formatting (black) deps = - isort black commands = - isort --check-only request_profiler black --check request_profiler [testenv:lint] +description = Python source code linting (ruff) deps = - flake8<5.0 - flake8-bandit - flake8-blind-except - flake8-docstrings - flake8-logging-format - flake8-print + ruff commands = - flake8 request_profiler + ruff request_profiler [testenv:mypy] +description = Python source code type hints (mypy) deps = mypy