From 17ca01bb71a418d9bed4b1d500e47006d78f30c7 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 11 Feb 2025 16:52:17 -0500 Subject: [PATCH 1/3] Add ruff configuration --- netbox_branching/tests/test_api.py | 2 +- netbox_branching/utilities.py | 2 +- netbox_branching/views.py | 2 +- pyproject.toml | 11 +++++++++++ 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/netbox_branching/tests/test_api.py b/netbox_branching/tests/test_api.py index 341dacd..af3852c 100644 --- a/netbox_branching/tests/test_api.py +++ b/netbox_branching/tests/test_api.py @@ -73,7 +73,7 @@ def test_with_branch_header(self): # Branch-aware API query header = { **self.header, - f'HTTP_X_NETBOX_BRANCH': branch.schema_id, + 'HTTP_X_NETBOX_BRANCH': branch.schema_id, } response = self.client.get(url, **header) results = self.get_results(response) diff --git a/netbox_branching/utilities.py b/netbox_branching/utilities.py index 56fbc6e..044c567 100644 --- a/netbox_branching/utilities.py +++ b/netbox_branching/utilities.py @@ -244,7 +244,7 @@ def get_active_branch(request): messages.error(request, f"Branch {branch} is not ready for use (status: {branch.status})") return None else: - messages.success(request, f"Deactivated branch") + messages.success(request, "Deactivated branch") request.COOKIES.pop(COOKIE_NAME, None) # Delete cookie if set return None diff --git a/netbox_branching/views.py b/netbox_branching/views.py index 38fb44c..af76b8b 100644 --- a/netbox_branching/views.py +++ b/netbox_branching/views.py @@ -274,7 +274,7 @@ class BranchArchiveView(generic.ObjectView): template_name = 'netbox_branching/branch_archive.html' def get_required_permission(self): - return f'netbox_branching.archive_branch' + return 'netbox_branching.archive_branch' @staticmethod def _enforce_status(request, branch): diff --git a/pyproject.toml b/pyproject.toml index 18f0efc..6eac76e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,17 @@ package-data = { "netbox_branching" = ["**/*", "templates/**"] } exclude-package-data = { netbox_branching = ["tests/*"] } license-files = ["LICENSE.md"] +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +extend-select = ["E1", "E2", "E3", "E501", "W"] +ignore = ["F403", "F405"] +preview = true + +[tool.ruff.format] +quote-style = "single" + [build-system] requires = ["setuptools>=43.0.0", "wheel"] build-backend = "setuptools.build_meta" From 42e6041a6273dcc73a7999a5597c9d62888228ec Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 11 Feb 2025 16:59:08 -0500 Subject: [PATCH 2/3] Linter cleanup --- netbox_branching/__init__.py | 2 +- netbox_branching/middleware.py | 2 +- netbox_branching/migrations/0001_initial.py | 84 +++++++++++++++++---- netbox_branching/models/branches.py | 8 +- 4 files changed, 77 insertions(+), 19 deletions(-) diff --git a/netbox_branching/__init__.py b/netbox_branching/__init__.py index 26c07ba..699bb77 100644 --- a/netbox_branching/__init__.py +++ b/netbox_branching/__init__.py @@ -31,7 +31,7 @@ class AppConfig(PluginConfig): def ready(self): super().ready() - from . import constants, events, search, signal_receivers + from . import constants, events, search, signal_receivers # noqa: F401 from .utilities import DynamicSchemaDict # Validate required settings diff --git a/netbox_branching/middleware.py b/netbox_branching/middleware.py index c339365..6fa9a2b 100644 --- a/netbox_branching/middleware.py +++ b/netbox_branching/middleware.py @@ -2,7 +2,7 @@ from django.http import HttpResponseBadRequest from .constants import COOKIE_NAME, QUERY_PARAM -from .utilities import activate_branch, is_api_request, get_active_branch +from .utilities import is_api_request, get_active_branch __all__ = ( 'BranchMiddleware', diff --git a/netbox_branching/migrations/0001_initial.py b/netbox_branching/migrations/0001_initial.py index e40b455..28192ba 100644 --- a/netbox_branching/migrations/0001_initial.py +++ b/netbox_branching/migrations/0001_initial.py @@ -7,7 +7,6 @@ class Migration(migrations.Migration): - initial = True dependencies = [ @@ -20,8 +19,7 @@ class Migration(migrations.Migration): operations = [ migrations.CreateModel( name='ObjectChange', - fields=[ - ], + fields=[], options={ 'proxy': True, 'indexes': [], @@ -35,7 +33,10 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('created', models.DateTimeField(auto_now_add=True, null=True)), ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder)), + ( + 'custom_field_data', + models.JSONField(blank=True, default=dict, encoder=utilities.json.CustomFieldJSONEncoder), + ), ('description', models.CharField(blank=True, max_length=200)), ('comments', models.TextField(blank=True)), ('name', models.CharField(max_length=100, unique=True)), @@ -43,8 +44,26 @@ class Migration(migrations.Migration): ('status', models.CharField(default='new', editable=False, max_length=50)), ('last_sync', models.DateTimeField(blank=True, editable=False, null=True)), ('merged_time', models.DateTimeField(blank=True, null=True)), - ('merged_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to=settings.AUTH_USER_MODEL)), - ('owner', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='branches', to=settings.AUTH_USER_MODEL)), + ( + 'merged_by', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to=settings.AUTH_USER_MODEL, + ), + ), + ( + 'owner', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='branches', + to=settings.AUTH_USER_MODEL, + ), + ), ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), ], options={ @@ -57,8 +76,20 @@ class Migration(migrations.Migration): name='AppliedChange', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), - ('change', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='application', to='core.objectchange')), - ('branch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='applied_changes', to='netbox_branching.branch')), + ( + 'change', + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, related_name='application', to='core.objectchange' + ), + ), + ( + 'branch', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name='applied_changes', + to='netbox_branching.branch', + ), + ), ], options={ 'verbose_name': 'applied change', @@ -72,8 +103,22 @@ class Migration(migrations.Migration): ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), ('time', models.DateTimeField(auto_now_add=True)), ('type', models.CharField(editable=False, max_length=50)), - ('branch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='events', to='netbox_branching.branch')), - ('user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='branch_events', to=settings.AUTH_USER_MODEL)), + ( + 'branch', + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, related_name='events', to='netbox_branching.branch' + ), + ), + ( + 'user', + models.ForeignKey( + blank=True, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='branch_events', + to=settings.AUTH_USER_MODEL, + ), + ), ], options={ 'verbose_name': 'branch event', @@ -92,9 +137,22 @@ class Migration(migrations.Migration): ('original', models.JSONField(blank=True, null=True)), ('modified', models.JSONField(blank=True, null=True)), ('current', models.JSONField(blank=True, null=True)), - ('conflicts', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=100), blank=True, editable=False, null=True, size=None)), - ('branch', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='netbox_branching.branch')), - ('object_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype')), + ( + 'conflicts', + django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(max_length=100), blank=True, editable=False, null=True, size=None + ), + ), + ( + 'branch', + models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='netbox_branching.branch'), + ), + ( + 'object_type', + models.ForeignKey( + on_delete=django.db.models.deletion.PROTECT, related_name='+', to='contenttypes.contenttype' + ), + ), ], options={ 'verbose_name': 'change diff', diff --git a/netbox_branching/models/branches.py b/netbox_branching/models/branches.py index 6ace090..624ac06 100644 --- a/netbox_branching/models/branches.py +++ b/netbox_branching/models/branches.py @@ -271,7 +271,7 @@ def sync(self, user, commit=True): if changes := self.get_unsynced_changes().order_by('time'): logger.info(f"Found {len(changes)} changes to sync") else: - logger.info(f"No changes found; aborting.") + logger.info("No changes found; aborting.") return # Update Branch status @@ -329,7 +329,7 @@ def merge(self, user, commit=True): if changes := self.get_unmerged_changes().order_by('time'): logger.info(f"Found {len(changes)} changes to merge") else: - logger.info(f"No changes found; aborting.") + logger.info("No changes found; aborting.") return # Update Branch status @@ -392,7 +392,7 @@ def revert(self, user, commit=True): logger.info(f'Reverting branch {self} ({self.schema_name})') if not self.merged: - raise Exception(f"Only merged branches can be reverted.") + raise Exception("Only merged branches can be reverted.") # Emit pre-revert signal pre_revert.send(sender=self.__class__, branch=self, user=user) @@ -401,7 +401,7 @@ def revert(self, user, commit=True): if changes := self.get_changes().order_by('-time'): logger.info(f"Found {len(changes)} changes to revert") else: - logger.info(f"No changes found; aborting.") + logger.info("No changes found; aborting.") return # Update Branch status From bacfc11f57f522db7389dc8a12f596d03ac1d1f2 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 11 Feb 2025 17:01:32 -0500 Subject: [PATCH 3/3] Replace pycodestyle with ruff --- .github/workflows/lint-tests.yaml | 5 ++--- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint-tests.yaml b/.github/workflows/lint-tests.yaml index 5861dc9..39ec9d6 100644 --- a/.github/workflows/lint-tests.yaml +++ b/.github/workflows/lint-tests.yaml @@ -34,9 +34,8 @@ jobs: pip install .[test] - name: Build documentation run: mkdocs build - - name: Run pycodestyle - run: | - pycodestyle --ignore=W504,E501 netbox_branching/ + - name: Run ruff + run: ruff check tests: runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/pyproject.toml b/pyproject.toml index 6eac76e..3c2c19c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ ] [project.optional-dependencies] -dev = ["check-manifest", "mkdocs", "mkdocs-material", "pycodestyle"] +dev = ["check-manifest", "mkdocs", "mkdocs-material", "ruff"] test = ["coverage", "pytest", "pytest-cov"] [project.urls]