From 1d25bc008f502c88424039e2d2d62a61b6add984 Mon Sep 17 00:00:00 2001 From: Mattia Giupponi Date: Fri, 29 May 2026 15:15:58 +0200 Subject: [PATCH 1/2] merge --- geonode/security/views.py | 4 ++-- geonode/upload/handlers/xml/handler.py | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/geonode/security/views.py b/geonode/security/views.py index 9c695c4fd9e..4c36840d4c8 100644 --- a/geonode/security/views.py +++ b/geonode/security/views.py @@ -278,8 +278,8 @@ def attributes_sats_refresh(request): layer.srid = "EPSG:4326" layer.set_ll_bbox_polygon([ll_bbox[0], ll_bbox[2], ll_bbox[1], ll_bbox[3]]) layer.save() - except Exception as e: - # traceback.print_exc() + except Exception: + logger.exception("Exception occurred while refreshing attributes/stats for resource uuid=%s", uuid) return HttpResponse( json.dumps({"success": "false", "message": f'Exception occurred: "{str(e)}"'}), status=302, diff --git a/geonode/upload/handlers/xml/handler.py b/geonode/upload/handlers/xml/handler.py index 182d9011277..71c46d6fa6d 100644 --- a/geonode/upload/handlers/xml/handler.py +++ b/geonode/upload/handlers/xml/handler.py @@ -93,8 +93,9 @@ def is_valid(files, user=None, **kwargs): try: with open(files.get("base_file")) as _xml: dlxml.fromstring(_xml.read().encode()) - except Exception as err: - raise InvalidXmlException(f"Uploaded document is not XML or is invalid: {str(err)}") + except Exception: + logger.warning("Invalid XML upload validation error", exc_info=True) + raise InvalidXmlException("Uploaded document is not XML or is invalid.") return True def handle_metadata_resource(self, _exec, dataset, original_handler): From 78899229e3d1434d4d447af8a6e5c39a6faf7bb6 Mon Sep 17 00:00:00 2001 From: Mattia Giupponi Date: Fri, 29 May 2026 16:09:19 +0200 Subject: [PATCH 2/2] Refactor with ruff --- .github/workflows/{flake8.yml => ruff.yml} | 17 ++--- .../management/commands/lib/gn20_to_24.py | 2 +- .../management/commands/lib/gn24_to_24.py | 2 +- .../0056_resourcebase_ll_bbox_polygon.py | 1 - .../0082_remove_dialogos_comment.py | 2 +- ...2_migrate and_remove_resourcebase_files.py | 1 - geonode/documents/forms.py | 2 +- .../migrations/0032_auto_20180412_0822.py | 2 +- ...op_resource_columns_from_document_table.py | 2 +- .../migrations/0027_auto_20180105_1631.py | 2 +- .../0006_harvester_availability_check_task.py | 3 +- ...er_harvester_default_access_permissions.py | 1 - geonode/layers/migrations/24_initial.py | 1 - geonode/layers/migrations/26_to_27.py | 3 +- .../migrations/0029_auto_20180412_0822.py | 2 +- geonode/notifications_helper.py | 2 +- geonode/security/views.py | 2 +- .../migrations/0028_auto_20171201_0640.py | 2 +- .../migrations/0029_auto_20171203_1624.py | 2 +- .../migrations/0038_auto_20180412_0822.py | 2 +- geonode/upload/handlers/common/vector.py | 2 +- .../0045_fixup_dynamic_shema_table_names.py | 2 - .../0049_move_data_from_importer_to_upload.py | 2 +- .../0051__align_resourcehandler_with_asset.py | 2 +- pyproject.toml | 67 +++++++++++++------ tasks.py | 2 +- 26 files changed, 73 insertions(+), 57 deletions(-) rename .github/workflows/{flake8.yml => ruff.yml} (55%) diff --git a/.github/workflows/flake8.yml b/.github/workflows/ruff.yml similarity index 55% rename from .github/workflows/flake8.yml rename to .github/workflows/ruff.yml index bba7c5511d5..b2d606dcf6f 100644 --- a/.github/workflows/flake8.yml +++ b/.github/workflows/ruff.yml @@ -2,10 +2,10 @@ name: "Code formatting" on: push: - branches: [ master, 4.* ] + branches: [ master, 5.* ] pull_request: # The branches below must be a subset of the branches above - branches: [ master, 4.* ] + branches: [ master, 5.* ] jobs: validate: @@ -27,15 +27,10 @@ jobs: with: python-version: ${{matrix.python-version}} - - name: Install flake8 & black - run: pip install $(grep -E '"(flake8|black)==[^"]+"' pyproject.toml | sed -E 's/^[^"]*"//; s/".*$//; s/,//') + - name: Install ruff + run: pip install $(grep "ruff==" pyproject.toml | sed -E 's/^[^"]*"//; s/".*$//; s/,//') - - name: "Check: flake8" + - name: "Check: ruff" run: | # stop the build if there are Python syntax errors or undefined names - flake8 geonode --count --select=E9,F63,F7,F82 --show-source --statistics - # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide - flake8 geonode --count --statistics - - - name: "Check: black" - run: black --check geonode + ruff check diff --git a/geonode/base/management/commands/lib/gn20_to_24.py b/geonode/base/management/commands/lib/gn20_to_24.py index e43a5fce3df..dcdabaa962f 100644 --- a/geonode/base/management/commands/lib/gn20_to_24.py +++ b/geonode/base/management/commands/lib/gn20_to_24.py @@ -76,7 +76,7 @@ def decode(self, json_string): obj['fields']['thumbnail_url'] = '' if 'distribution_url' in obj['fields']: - if not obj['fields']['distribution_url'] is None and 'layers' in obj['fields']['distribution_url']: + if obj['fields']['distribution_url'] is not None and 'layers' in obj['fields']['distribution_url']: obj['fields']['polymorphic_ctype'] = ["layers", "layer"] diff --git a/geonode/base/management/commands/lib/gn24_to_24.py b/geonode/base/management/commands/lib/gn24_to_24.py index 30794ea0d0c..f4ca19f1170 100644 --- a/geonode/base/management/commands/lib/gn24_to_24.py +++ b/geonode/base/management/commands/lib/gn24_to_24.py @@ -73,7 +73,7 @@ def decode(self, json_string): obj['fields']['owner'] = [self.owner] if 'distribution_url' in obj['fields']: - if not obj['fields']['distribution_url'] is None and 'layers' in obj['fields']['distribution_url']: + if obj['fields']['distribution_url'] is not None and 'layers' in obj['fields']['distribution_url']: try: p = '(?Phttp.*://)?(?P[^:/ ]+).?(?P[0-9]*)(?P.*)' m = re.search(p, obj['fields']['distribution_url']) diff --git a/geonode/base/migrations/0056_resourcebase_ll_bbox_polygon.py b/geonode/base/migrations/0056_resourcebase_ll_bbox_polygon.py index 20e8f044fb7..1a98b33cf05 100644 --- a/geonode/base/migrations/0056_resourcebase_ll_bbox_polygon.py +++ b/geonode/base/migrations/0056_resourcebase_ll_bbox_polygon.py @@ -2,7 +2,6 @@ import logging import django.contrib.gis.db.models.fields -from django.contrib.gis.geos import Polygon from django.db import migrations diff --git a/geonode/base/migrations/0082_remove_dialogos_comment.py b/geonode/base/migrations/0082_remove_dialogos_comment.py index 98f184e50ac..b983aeca53c 100644 --- a/geonode/base/migrations/0082_remove_dialogos_comment.py +++ b/geonode/base/migrations/0082_remove_dialogos_comment.py @@ -1,6 +1,6 @@ # Generated by Django 3.2.12 on 2022-04-11 22:56 -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/base/migrations/0092_migrate and_remove_resourcebase_files.py b/geonode/base/migrations/0092_migrate and_remove_resourcebase_files.py index ea89c795557..674372bbd6d 100644 --- a/geonode/base/migrations/0092_migrate and_remove_resourcebase_files.py +++ b/geonode/base/migrations/0092_migrate and_remove_resourcebase_files.py @@ -5,7 +5,6 @@ from django.db import migrations from django.db.models import Q -from django.conf import settings from django.contrib.auth import get_user_model from django.urls import reverse diff --git a/geonode/documents/forms.py b/geonode/documents/forms.py index 155e9cce6ae..132f95d1407 100644 --- a/geonode/documents/forms.py +++ b/geonode/documents/forms.py @@ -138,7 +138,7 @@ def clean_doc_file(self): """ doc_file = self.cleaned_data.get("doc_file") - if doc_file and not os.path.splitext(doc_file.name)[1].lower()[1:] in settings.ALLOWED_DOCUMENT_TYPES: + if doc_file and os.path.splitext(doc_file.name)[1].lower()[1:] not in settings.ALLOWED_DOCUMENT_TYPES: logger.debug("This file type is not allowed") raise forms.ValidationError(_("This file type is not allowed")) diff --git a/geonode/documents/migrations/0032_auto_20180412_0822.py b/geonode/documents/migrations/0032_auto_20180412_0822.py index 1b09621c193..1581a103195 100644 --- a/geonode/documents/migrations/0032_auto_20180412_0822.py +++ b/geonode/documents/migrations/0032_auto_20180412_0822.py @@ -1,4 +1,4 @@ -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/documents/migrations/27_drop_resource_columns_from_document_table.py b/geonode/documents/migrations/27_drop_resource_columns_from_document_table.py index f59f16b1c2c..a8e7341f38e 100644 --- a/geonode/documents/migrations/27_drop_resource_columns_from_document_table.py +++ b/geonode/documents/migrations/27_drop_resource_columns_from_document_table.py @@ -1,4 +1,4 @@ -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/groups/migrations/0027_auto_20180105_1631.py b/geonode/groups/migrations/0027_auto_20180105_1631.py index 123006a89e1..b44a81ca675 100644 --- a/geonode/groups/migrations/0027_auto_20180105_1631.py +++ b/geonode/groups/migrations/0027_auto_20180105_1631.py @@ -1,4 +1,4 @@ -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/harvesting/migrations/0006_harvester_availability_check_task.py b/geonode/harvesting/migrations/0006_harvester_availability_check_task.py index 017dd288da6..ad6e344832b 100644 --- a/geonode/harvesting/migrations/0006_harvester_availability_check_task.py +++ b/geonode/harvesting/migrations/0006_harvester_availability_check_task.py @@ -1,7 +1,6 @@ # Generated by Django 2.2.16 on 2021-04-28 11:47 -from django.db import migrations, models -import django.db.models.deletion +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/harvesting/migrations/0022_alter_harvester_default_access_permissions.py b/geonode/harvesting/migrations/0022_alter_harvester_default_access_permissions.py index 235ccb75be5..aac81538bd3 100644 --- a/geonode/harvesting/migrations/0022_alter_harvester_default_access_permissions.py +++ b/geonode/harvesting/migrations/0022_alter_harvester_default_access_permissions.py @@ -1,7 +1,6 @@ # Generated by Django 3.2.4 on 2021-06-23 17:19 from django.db import migrations, models -import geonode.harvesting.models class Migration(migrations.Migration): diff --git a/geonode/layers/migrations/24_initial.py b/geonode/layers/migrations/24_initial.py index 5744398a19a..a2a2e4079df 100755 --- a/geonode/layers/migrations/24_initial.py +++ b/geonode/layers/migrations/24_initial.py @@ -1,5 +1,4 @@ from django.db import migrations, models -import datetime from django.conf import settings from django.utils.timezone import now import django.core.files.storage diff --git a/geonode/layers/migrations/26_to_27.py b/geonode/layers/migrations/26_to_27.py index 44d27abb3e7..a253eaa7f1e 100755 --- a/geonode/layers/migrations/26_to_27.py +++ b/geonode/layers/migrations/26_to_27.py @@ -1,5 +1,4 @@ -from django.db import migrations, models -from django.db.models import F +from django.db import migrations def copy_typename(apps, schema_editor): Layer = apps.get_model('layers', 'layer') diff --git a/geonode/maps/migrations/0029_auto_20180412_0822.py b/geonode/maps/migrations/0029_auto_20180412_0822.py index b09826f8d71..ea4bf22bef6 100644 --- a/geonode/maps/migrations/0029_auto_20180412_0822.py +++ b/geonode/maps/migrations/0029_auto_20180412_0822.py @@ -1,4 +1,4 @@ -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/notifications_helper.py b/geonode/notifications_helper.py index 2c9d684d47a..c693320476a 100644 --- a/geonode/notifications_helper.py +++ b/geonode/notifications_helper.py @@ -115,7 +115,7 @@ def get_notification_recipients(notice_type_label, exclude_user=None, resource=N try: if not user.is_superuser and not user.has_perm("view_resourcebase", resource.get_self_resource()): exclude_users_ids.append(user.id) - if user.pk == resource.owner.pk and not notice_type_label.split("_")[-1] in ( + if user.pk == resource.owner.pk and notice_type_label.split("_")[-1] not in ( "updated", "rated", "approved", diff --git a/geonode/security/views.py b/geonode/security/views.py index 4c36840d4c8..f0c42b7f96d 100644 --- a/geonode/security/views.py +++ b/geonode/security/views.py @@ -281,7 +281,7 @@ def attributes_sats_refresh(request): except Exception: logger.exception("Exception occurred while refreshing attributes/stats for resource uuid=%s", uuid) return HttpResponse( - json.dumps({"success": "false", "message": f'Exception occurred: "{str(e)}"'}), + json.dumps({"success": "false", "message": 'Exception occurred please see the logs"'}), status=302, content_type="text/plain", ) diff --git a/geonode/services/migrations/0028_auto_20171201_0640.py b/geonode/services/migrations/0028_auto_20171201_0640.py index b3e6acc35a8..99b64cf4dfe 100644 --- a/geonode/services/migrations/0028_auto_20171201_0640.py +++ b/geonode/services/migrations/0028_auto_20171201_0640.py @@ -1,4 +1,4 @@ -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/services/migrations/0029_auto_20171203_1624.py b/geonode/services/migrations/0029_auto_20171203_1624.py index fbaaa19d05b..1a63e9e9031 100644 --- a/geonode/services/migrations/0029_auto_20171203_1624.py +++ b/geonode/services/migrations/0029_auto_20171203_1624.py @@ -1,4 +1,4 @@ -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/services/migrations/0038_auto_20180412_0822.py b/geonode/services/migrations/0038_auto_20180412_0822.py index df777157078..fe0a24c378d 100644 --- a/geonode/services/migrations/0038_auto_20180412_0822.py +++ b/geonode/services/migrations/0038_auto_20180412_0822.py @@ -1,4 +1,4 @@ -from django.db import migrations, models +from django.db import migrations class Migration(migrations.Migration): diff --git a/geonode/upload/handlers/common/vector.py b/geonode/upload/handlers/common/vector.py index 59ebf0f08b2..34e6d84f795 100644 --- a/geonode/upload/handlers/common/vector.py +++ b/geonode/upload/handlers/common/vector.py @@ -1125,7 +1125,7 @@ def upsert_validation(self, files, execution_id, **kwargs: dict) -> Tuple[bool, if "authority" in field and not skip_geom_eval: if db_value := target_field.model_schema.as_model().objects.first(): skip_geom_eval = True - if not str(db_value.geom.srid) in field["authority"]: + if str(db_value.geom.srid) not in field["authority"]: errors.append( f"The file provided have a different authority ({field['authority']}) compared to the one in the DB: {db_value}" ) diff --git a/geonode/upload/migrations/0045_fixup_dynamic_shema_table_names.py b/geonode/upload/migrations/0045_fixup_dynamic_shema_table_names.py index ea27538966b..64b13ba625e 100644 --- a/geonode/upload/migrations/0045_fixup_dynamic_shema_table_names.py +++ b/geonode/upload/migrations/0045_fixup_dynamic_shema_table_names.py @@ -1,7 +1,5 @@ from django.db import migrations import logging -from django.db import ProgrammingError -from django.db import connections logger = logging.getLogger("importer") diff --git a/geonode/upload/migrations/0049_move_data_from_importer_to_upload.py b/geonode/upload/migrations/0049_move_data_from_importer_to_upload.py index 349d6e5c547..907a1b9757c 100644 --- a/geonode/upload/migrations/0049_move_data_from_importer_to_upload.py +++ b/geonode/upload/migrations/0049_move_data_from_importer_to_upload.py @@ -1,6 +1,6 @@ # Generated by Django 4.2.9 on 2024-09-06 14:46 -from django.db import migrations, models +from django.db import migrations from django.db import connection from geonode.upload.models import ResourceHandlerInfo diff --git a/geonode/upload/migrations/0051__align_resourcehandler_with_asset.py b/geonode/upload/migrations/0051__align_resourcehandler_with_asset.py index 8122d8d2e49..73151e84cbb 100644 --- a/geonode/upload/migrations/0051__align_resourcehandler_with_asset.py +++ b/geonode/upload/migrations/0051__align_resourcehandler_with_asset.py @@ -41,7 +41,7 @@ def dataset_migration(apps, _): execution_id=None ) else: - logger.debug(f"resourcehandler info already exists for the resource") + logger.debug("resourcehandler info already exists for the resource") class Migration(migrations.Migration): diff --git a/pyproject.toml b/pyproject.toml index 0467a2b0a1b..2834b014f2f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -142,8 +142,6 @@ dependencies = [ # tests "coverage==7.5.1", "requests-toolbelt==1.0.0", - "flake8==7.3.0", - "black==24.4.2", "pytest==8.4.2", "pytest-bdd==7.1.2", "splinter==0.21.0", @@ -161,13 +159,12 @@ dependencies = [ # dependency for XLSX handler "python-calamine==0.6.2", "python-magic==0.4.27", + "ruff==0.15.14", ] [project.optional-dependencies] dev = [ "pytest==8.4.2", - "flake8==7.3.0", - "black==24.4.2", "coverage==7.5.1", ] docs = [ @@ -191,18 +188,50 @@ include = ["geonode*"] [tool.setuptools.dynamic] version = {attr = "geonode.__version__"} -[tool.black] -line-length = 120 -target-version = ['py310', 'py311'] -exclude = ''' -/( - geonode/.*/migrations/.* - | geonode/.*/settings.py - | management - | scripts - | docs - | static - | migrations - | node_modules -)/ -''' + +[tool.ruff] + +exclude = [ + "geonode/*/migrations/*", + "geonode/**/settings.py", + "management", + "scripts", + "docs", + "static", + "migrations", + "node_modules", +] + +# Same as Black. +line-length = 88 +indent-width = 4 + +target-version = "py312" + + +[tool.ruff.lint] +# E and F are the standard Flake8 rules +select = ["E4", "E7", "E9", "F"] +ignore = ["E203", "E731"] +fixable = ["ALL"] +unfixable = [] + +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" + +[tool.ruff.lint.isort] +# This makes it behave like modern Black-compatible isort +combine-as-imports = true +lines-after-imports = 2 + +[tool.ruff.format] +# Like Black, use double quotes for strings. +quote-style = "double" + +# Like Black, indent with spaces, rather than tabs. +indent-style = "space" + +# Like Black, respect magic trailing commas. +skip-magic-trailing-comma = false + +# Like Black, automatically detect the appropriate line ending. +line-ending = "auto" diff --git a/tasks.py b/tasks.py index 86513d3380b..e7075dcfdf6 100755 --- a/tasks.py +++ b/tasks.py @@ -448,7 +448,7 @@ def _is_valid_ip(ip): try: ipaddress.IPv4Address(ip) return True - except Exception as e: + except Exception: return False