From a996af8fc06359c46a34837a8e665bd83ca332bc Mon Sep 17 00:00:00 2001
From: Mohammad Torkashvand <mohammad.torkashvand@geant.org>
Date: Mon, 29 Apr 2024 12:02:00 +0200
Subject: [PATCH] fix ruff errors

---
 gso/__init__.py                         |  2 +-
 gso/schedules/scheduling.py             | 33 ++++++++++++++-----------
 gso/schedules/task_vacuum.py            |  4 +--
 gso/schedules/validate_products.py      |  4 +--
 gso/schedules/validate_subscriptions.py |  4 +--
 gso/services/infoblox.py                |  2 +-
 gso/utils/shared_enums.py               | 11 ++++++---
 gso/worker.py                           |  2 +-
 pyproject.toml                          |  3 +++
 setup.py                                |  2 ++
 test/auth/test_oidc_policy_helper.py    |  4 +--
 test/conftest.py                        |  2 +-
 test/schedules/test_scheduling.py       | 30 ++++++++++++----------
 test/utils/test_helpers.py              |  4 +--
 test/workflows/__init__.py              |  3 ++-
 15 files changed, 65 insertions(+), 45 deletions(-)

diff --git a/gso/__init__.py b/gso/__init__.py
index 94c8f5fa..ecdfd940 100644
--- a/gso/__init__.py
+++ b/gso/__init__.py
@@ -28,7 +28,7 @@ def init_worker_app() -> OrchestratorCore:
 
 def init_cli_app() -> typer.Typer:
     """Initialise :term:`GSO` as a CLI application."""
-    from gso.cli import imports, netbox
+    from gso.cli import imports, netbox  # noqa: PLC0415
 
     cli_app.add_typer(imports.app, name="import-cli")
     cli_app.add_typer(netbox.app, name="netbox-cli")
diff --git a/gso/schedules/scheduling.py b/gso/schedules/scheduling.py
index 2e83fab3..b0e22a09 100644
--- a/gso/schedules/scheduling.py
+++ b/gso/schedules/scheduling.py
@@ -7,16 +7,21 @@ from typing import Any
 
 from celery import current_app
 from celery.schedules import crontab
+from pydantic import BaseModel
 
 
-def scheduler(
-    name: str,
-    minute: str = "*",
-    hour: str = "*",
-    day_of_week: str = "*",
-    day_of_month: str = "*",
-    month_of_year: str = "*",
-) -> Callable[[Callable], Callable]:
+class CronScheduleConfig(BaseModel):
+    """Configuration for scheduling a task using crontab-like timing parameters."""
+
+    name: str
+    minute: str = "*"
+    hour: str = "*"
+    day_of_week: str = "*"
+    day_of_month: str = "*"
+    month_of_year: str = "*"
+
+
+def scheduler(cron_scheduler_config: CronScheduleConfig) -> Callable[[Callable], Callable]:
     """Schedule a Celery task using crontab-like timing.
 
     Examples
@@ -44,14 +49,14 @@ def scheduler(
 
         task_path = f"{module.__name__}.{task_func.__name__}"
         current_app.conf.beat_schedule[task_func.__name__] = {
-            "name": name,
+            "name": cron_scheduler_config.name,
             "task": task_path,
             "schedule": crontab(
-                minute=minute,
-                hour=hour,
-                day_of_month=day_of_month,
-                month_of_year=month_of_year,
-                day_of_week=day_of_week,
+                minute=cron_scheduler_config.minute,
+                hour=cron_scheduler_config.hour,
+                day_of_month=cron_scheduler_config.day_of_month,
+                month_of_year=cron_scheduler_config.month_of_year,
+                day_of_week=cron_scheduler_config.day_of_week,
             ),
         }
 
diff --git a/gso/schedules/task_vacuum.py b/gso/schedules/task_vacuum.py
index 98e05343..be04380f 100644
--- a/gso/schedules/task_vacuum.py
+++ b/gso/schedules/task_vacuum.py
@@ -2,12 +2,12 @@
 
 from orchestrator.services.processes import start_process
 
-from gso.schedules.scheduling import scheduler
+from gso.schedules.scheduling import CronScheduleConfig, scheduler
 from gso.worker import celery
 
 
 @celery.task
-@scheduler(name="Clean up tasks", hour="*/6")
+@scheduler(CronScheduleConfig(name="Clean up tasks", hour="*/6"))
 def vacuum_tasks() -> None:
     """Run all cleanup tasks every 6 hours."""
     start_process("task_clean_up_tasks")
diff --git a/gso/schedules/validate_products.py b/gso/schedules/validate_products.py
index cb9ecc67..580c7540 100644
--- a/gso/schedules/validate_products.py
+++ b/gso/schedules/validate_products.py
@@ -2,13 +2,13 @@
 
 from orchestrator.services.processes import start_process
 
-from gso.schedules.scheduling import scheduler
+from gso.schedules.scheduling import CronScheduleConfig, scheduler
 from gso.services.subscriptions import count_incomplete_validate_products
 from gso.worker import celery
 
 
 @celery.task
-@scheduler(name="Validate Products and inactive subscriptions", minute="30", hour="2")
+@scheduler(CronScheduleConfig(name="Validate Products and inactive subscriptions", minute="30", hour="2"))
 def validate_products() -> None:
     """Validate all products."""
     if count_incomplete_validate_products() > 0:
diff --git a/gso/schedules/validate_subscriptions.py b/gso/schedules/validate_subscriptions.py
index 7c440435..9e79ec91 100644
--- a/gso/schedules/validate_subscriptions.py
+++ b/gso/schedules/validate_subscriptions.py
@@ -5,7 +5,7 @@ from orchestrator.services.processes import get_execution_context
 from orchestrator.services.subscriptions import TARGET_DEFAULT_USABLE_MAP, WF_USABLE_MAP
 from orchestrator.targets import Target
 
-from gso.schedules.scheduling import scheduler
+from gso.schedules.scheduling import CronScheduleConfig, scheduler
 from gso.services.subscriptions import get_insync_subscriptions
 from gso.worker import celery
 
@@ -13,7 +13,7 @@ logger = structlog.get_logger(__name__)
 
 
 @celery.task
-@scheduler(name="Subscriptions Validator", minute="10", hour="0")
+@scheduler(CronScheduleConfig(name="Subscriptions Validator", minute="10", hour="0"))
 def validate_subscriptions() -> None:
     """Validate all subscriptions using their corresponding validation workflow."""
     subscriptions = get_insync_subscriptions()
diff --git a/gso/services/infoblox.py b/gso/services/infoblox.py
index 514c55cb..874ee6f5 100644
--- a/gso/services/infoblox.py
+++ b/gso/services/infoblox.py
@@ -37,7 +37,7 @@ def _setup_connection() -> tuple[connector.Connector, IPAMParams]:
     return connector.Connector(options), oss
 
 
-def _allocate_network(
+def _allocate_network(  # noqa: PLR0917
     conn: connector.Connector,
     dns_view: str,
     network_view: str,
diff --git a/gso/utils/shared_enums.py b/gso/utils/shared_enums.py
index 1054876f..6a590515 100644
--- a/gso/utils/shared_enums.py
+++ b/gso/utils/shared_enums.py
@@ -1,13 +1,18 @@
 """Shared choices for the different models."""
 
 import ipaddress
-from typing import Annotated
+from typing import Annotated, Any
 
 from pydantic import Field, PlainSerializer
 from pydantic_forms.types import strEnum
 from typing_extensions import Doc
 
 
+def convert_to_str(value: Any) -> str:
+    """Convert the value to a string."""
+    return str(value)
+
+
 class Vendor(strEnum):
     """Enumerator for the different product vendors that are supported."""
 
@@ -29,11 +34,11 @@ PortNumber = Annotated[
 
 
 IPv4AddressType = Annotated[
-    ipaddress.IPv4Address, PlainSerializer(lambda ip: str(ip), return_type=str, when_used="always")
+    ipaddress.IPv4Address, PlainSerializer(convert_to_str, return_type=str, when_used="always")
 ]
 
 IPv6AddressType = Annotated[
-    ipaddress.IPv6Address, PlainSerializer(lambda ip: str(ip), return_type=str, when_used="always")
+    ipaddress.IPv6Address, PlainSerializer(convert_to_str, return_type=str, when_used="always")
 ]
 
 
diff --git a/gso/worker.py b/gso/worker.py
index b1a3db2c..b2abfe6f 100644
--- a/gso/worker.py
+++ b/gso/worker.py
@@ -9,7 +9,7 @@ from gso.settings import load_oss_params
 class OrchestratorCelery(Celery):
     """A :term:`GSO` instance that functions as a Celery worker."""
 
-    def on_init(self) -> None:
+    def on_init(self) -> None:  # noqa: PLR6301
         """Initialise a new Celery worker."""
         init_worker_app()
 
diff --git a/pyproject.toml b/pyproject.toml
index 34c2cc10..376371b7 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -113,3 +113,6 @@ filterwarnings = [
     "ignore",
     "default:::gso",
 ]
+[tool.ruff.lint.per-file-ignores]
+"test/*" = ["PLR0917", "S101", "D104", "D105", "D103", "D100", "ARG001", "D102", "PLR2004", "D101", "D106", "D107", "PLR0914", "PLC0415", "PLC2701"]
+"gso/workflows/*" = ["PLR0917", "PLR0914"]
\ No newline at end of file
diff --git a/setup.py b/setup.py
index 08fa01b8..6339e95a 100644
--- a/setup.py
+++ b/setup.py
@@ -1,3 +1,5 @@
+"""Setup script for the GÉANT Service Orchestrator."""
+
 from setuptools import find_packages, setup
 
 setup(
diff --git a/test/auth/test_oidc_policy_helper.py b/test/auth/test_oidc_policy_helper.py
index 767e3442..46b934ca 100644
--- a/test/auth/test_oidc_policy_helper.py
+++ b/test/auth/test_oidc_policy_helper.py
@@ -268,7 +268,7 @@ async def test_oidc_user_call_no_token(oidc_user, mock_request):
         mock_post.return_value = MagicMock(status_code=200, json=lambda: {"active": False})
         mock_get.return_value = MagicMock(status_code=200, json=dict)
 
-        result = await oidc_user.__call__(mock_request)
+        result = await oidc_user.__call__(mock_request)  # noqa: PLC2801
 
     assert result is None
 
@@ -281,7 +281,7 @@ async def test_oidc_user_call_token_from_request(oidc_user, mock_request, mock_a
     oidc_user.introspect_token = AsyncMock(return_value={"active": True})
     oidc_user.userinfo = AsyncMock(return_value=OIDCUserModel({"sub": "123", "name": "John Doe"}))
 
-    result = await oidc_user.__call__(mock_request)
+    result = await oidc_user.__call__(mock_request)  # noqa: PLC2801
 
     assert isinstance(result, OIDCUserModel)
     assert result["sub"] == "123"
diff --git a/test/conftest.py b/test/conftest.py
index a5d42798..8fae41e7 100644
--- a/test/conftest.py
+++ b/test/conftest.py
@@ -57,7 +57,7 @@ def pytest_collection_modifyitems(config, items):
 
 
 class UseJuniperSide(strEnum):
-    """Define on tests on which side to use Juniper router"""
+    """Define on tests on which side to use Juniper router."""
 
     NONE = "none"
     SIDE_A = "side_a"
diff --git a/test/schedules/test_scheduling.py b/test/schedules/test_scheduling.py
index 82168eb4..17811174 100644
--- a/test/schedules/test_scheduling.py
+++ b/test/schedules/test_scheduling.py
@@ -3,7 +3,7 @@ from unittest.mock import MagicMock, patch
 import pytest
 from orchestrator.targets import Target
 
-from gso.schedules.scheduling import scheduler
+from gso.schedules.scheduling import CronScheduleConfig, scheduler
 
 
 @pytest.fixture(scope="module")
@@ -42,12 +42,14 @@ def test_scheduler_updates_beat_schedule(mock_celery):
     mock_celery.conf.beat_schedule = {}
 
     @scheduler(
-        name="A cool task",
-        minute="0",
-        hour="0",
-        day_of_week="*",
-        day_of_month="*",
-        month_of_year="*",
+        CronScheduleConfig(
+            name="A cool task",
+            minute="0",
+            hour="0",
+            day_of_week="*",
+            day_of_month="*",
+            month_of_year="*",
+        )
     )
     def mock_task():
         return "task result"
@@ -64,12 +66,14 @@ def test_scheduled_task_still_works():
     """Ensure that the scheduler decorator does not change the behavior of the function it decorates."""
 
     @scheduler(
-        name="A cool task",
-        minute="0",
-        hour="0",
-        day_of_week="*",
-        day_of_month="*",
-        month_of_year="*",
+        CronScheduleConfig(
+            name="A cool task",
+            minute="0",
+            hour="0",
+            day_of_week="*",
+            day_of_month="*",
+            month_of_year="*",
+        )
     )
     def mock_task():
         return "task result"
diff --git a/test/utils/test_helpers.py b/test/utils/test_helpers.py
index 5dee0aa8..e80e6f30 100644
--- a/test/utils/test_helpers.py
+++ b/test/utils/test_helpers.py
@@ -23,7 +23,7 @@ def mock_netbox_client():
 
 @pytest.fixture()
 def generate_tt_numbers(faker, request):
-    """Generator for valid and invalid tt numbers."""
+    """Get a Generator for valid and invalid tt numbers."""
     valid_count = request.param.get("valid", 0)
     invalid_count = request.param.get("invalid", 0)
 
@@ -78,7 +78,7 @@ def test_nokia_router_with_interfaces_returns_choice(mock_router, mock_netbox_cl
 
 @pytest.mark.parametrize("generate_tt_numbers", [{"valid": 5, "invalid": 3}], indirect=True)
 def test_tt_number(generate_tt_numbers):
-    """Test different TT numbers"""
+    """Test different TT numbers."""
     for tt_number, is_valid in generate_tt_numbers:
         if is_valid:
             assert validate_tt_number(tt_number) == tt_number
diff --git a/test/workflows/__init__.py b/test/workflows/__init__.py
index 246d2b76..b44bace9 100644
--- a/test/workflows/__init__.py
+++ b/test/workflows/__init__.py
@@ -157,7 +157,8 @@ class WorkflowInstanceForTests(LazyWorkflowInstance):
         This can be as simple as merely importing a workflow function. However, if it concerns a workflow generating
         function, that function will be called with or without arguments as specified.
 
-        Returns:
+        Returns
+        -------
             A workflow function.
 
         """
-- 
GitLab