From dc89a20b112acd627823c4e1cdc6ab9ca791f1c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Tue, 23 Apr 2024 22:12:04 +0200 Subject: [PATCH] chore: configure ruff --- .pre-commit-config.yaml | 13 +----------- canaille/app/configuration.py | 5 +++-- canaille/app/flask.py | 4 ++-- canaille/app/forms.py | 4 ++-- canaille/backends/__init__.py | 19 ++++++++--------- canaille/backends/models.py | 11 +++++----- canaille/core/commands.py | 2 -- canaille/core/models.py | 8 +++---- canaille/oidc/basemodels.py | 3 +-- canaille/oidc/configuration.py | 3 ++- pyproject.toml | 17 ++++++++++++++- tests/backends/ldap/test_object_class.py | 1 - tests/core/test_forgotten_password.py | 27 ++++++++++++++++-------- 13 files changed, 63 insertions(+), 54 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 38b0e709..cb936316 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: 'v0.3.7' + rev: 'v0.4.1' hooks: - id: ruff args: [--fix, --exit-non-zero-on-fix] @@ -15,21 +15,10 @@ repos: - id: end-of-file-fixer exclude: "\\.svg$|\\.map$|\\.min\\.css$|\\.min\\.js$|\\.po$|\\.pot$" - id: check-toml - - repo: https://github.com/pycqa/isort - rev: "5.13.2" - hooks: - - id: isort - name: isort (python) - args: ["--force-single-line-imports", "--profile", "black"] - repo: https://github.com/PyCQA/docformatter rev: v1.7.5 hooks: - id: docformatter - - repo: https://github.com/asottile/pyupgrade - rev: v3.15.2 - hooks: - - id: pyupgrade - args: ["--py38-plus"] - repo: https://github.com/rtts/djhtml rev: 3.0.6 hooks: diff --git a/canaille/app/configuration.py b/canaille/app/configuration.py index a42c834c..c70231db 100644 --- a/canaille/app/configuration.py +++ b/canaille/app/configuration.py @@ -17,8 +17,9 @@ ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) class RootSettings(BaseSettings): """The top-level namespace contains holds the configuration settings - unrelated to Canaille. The configuration paramateres from the following - libraries can be used: + unrelated to Canaille. + + The configuration paramateres from the following libraries can be used: - :doc:`Flask ` - :doc:`Flask-WTF ` diff --git a/canaille/app/flask.py b/canaille/app/flask.py index 153119dc..de96c000 100644 --- a/canaille/app/flask.py +++ b/canaille/app/flask.py @@ -36,7 +36,7 @@ def current_user(): def login_user(user): - """Opens a session for the user.""" + """Open a session for the user.""" g.user = user try: previous = ( @@ -50,7 +50,7 @@ def login_user(user): def logout_user(): - """Closes the user session.""" + """Close the user session.""" try: session["user_id"].pop() del g.user diff --git a/canaille/app/forms.py b/canaille/app/forms.py index 5b2e8805..679ed42a 100644 --- a/canaille/app/forms.py +++ b/canaille/app/forms.py @@ -72,7 +72,7 @@ class HTMXFormMixin: render_field_extra_context = {} def field_from_name(self, field_name): - """Returns a tuple containing a field and its rendering context.""" + """Return a tuple containing a field and its rendering context.""" if self.SEPARATOR not in field_name: field = self[field_name] if field_name in self else None return field, {} @@ -120,7 +120,7 @@ class HTMXFormMixin: abort(response) def form_control(self): - """Checks wether the current request is the result of the users adding + """Check wether the current request is the result of the users adding or removing a field from a FieldList.""" FIELDLIST_ADD_BUTTON = "fieldlist_add" FIELDLIST_REMOVE_BUTTON = "fieldlist_remove" diff --git a/canaille/backends/__init__.py b/canaille/backends/__init__.py index a03f4416..93908f34 100644 --- a/canaille/backends/__init__.py +++ b/canaille/backends/__init__.py @@ -34,21 +34,20 @@ class BaseBackend: @classmethod def install(self, config): - """This methods prepares the database to host canaille data.""" + """Prepare the database to host canaille data.""" raise NotImplementedError() def setup(self): - """This method will be called before each http request, it should open - the connection to the backend.""" + """Is called before each http request, it should open the connection to + the backend.""" def teardown(self): - """This method will be called after each http request, it should close - the connections to the backend.""" + """Is called after each http request, it should close the connections + to the backend.""" @classmethod def validate(cls, config): - """This method should validate the config part dedicated to the - backend. + """Validate the config part dedicated to the backend. It should raise :class:`~canaille.configuration.ConfigurationError` when errors are met. @@ -56,15 +55,15 @@ class BaseBackend: raise NotImplementedError() def check_user_password(self, user, password: str) -> bool: - """Checks if the password matches the user password in the database.""" + """Check if the password matches the user password in the database.""" raise NotImplementedError() def set_user_password(self, user, password: str): - """Sets a password for the user.""" + """Set a password for the user.""" raise NotImplementedError() def has_account_lockability(self): - """Indicates wether the backend supports locking user accounts.""" + """Indicate wether the backend supports locking user accounts.""" raise NotImplementedError() def register_models(self): diff --git a/canaille/backends/models.py b/canaille/backends/models.py index 699b9f09..c115dd3c 100644 --- a/canaille/backends/models.py +++ b/canaille/backends/models.py @@ -89,8 +89,9 @@ class BackendModel: @classmethod def query(cls, **kwargs): - """ - Performs a query on the database and return a collection of instances. + """Perform a query on the database and return a collection of + instances. + Parameters can be any valid attribute with the expected value: >>> User.query(first_name="George") @@ -120,11 +121,11 @@ class BackendModel: raise NotImplementedError() def save(self): - """Validates the current modifications in the database.""" + """Validate the current modifications in the database.""" raise NotImplementedError() def delete(self): - """Removes the current instance from the database.""" + """Remove the current instance from the database.""" raise NotImplementedError() def update(self, **kwargs): @@ -145,7 +146,7 @@ class BackendModel: setattr(self, attribute, value) def reload(self): - """Cancels the unsaved modifications. + """Cancel the unsaved modifications. >>> user = User.get(user_name="george") >>> user.display_name diff --git a/canaille/core/commands.py b/canaille/core/commands.py index bf743461..b5f34643 100644 --- a/canaille/core/commands.py +++ b/canaille/core/commands.py @@ -26,7 +26,6 @@ def populate(ctx, nb): @with_backendcontext def users(ctx): """Populate the database with generated random users.""" - from canaille.core.populate import fake_users fake_users(ctx.obj["number"]) @@ -43,7 +42,6 @@ def users(ctx): @with_backendcontext def groups(ctx, nb_users_max): """Populate the database with generated random groups.""" - from canaille.core.populate import fake_groups fake_groups(ctx.obj["number"], nb_users_max) diff --git a/canaille/core/models.py b/canaille/core/models.py index da0b3976..caad8ae9 100644 --- a/canaille/core/models.py +++ b/canaille/core/models.py @@ -11,8 +11,7 @@ from canaille.core.configuration import Permission class User(Model): - """ - User model, based on the `SCIM User schema + """User model, based on the `SCIM User schema `_, `Entreprise User Schema Extension `_ @@ -249,7 +248,7 @@ class User(Model): _permissions = None def has_password(self) -> bool: - """Checks wether a password has been set for the user.""" + """Check wether a password has been set for the user.""" return self.password is not None def can_read(self, field: str): @@ -323,8 +322,7 @@ class User(Model): class Group(Model): - """ - User model, based on the `SCIM Group schema + """User model, based on the `SCIM Group schema `_. """ diff --git a/canaille/oidc/basemodels.py b/canaille/oidc/basemodels.py index 02d25f30..17021c84 100644 --- a/canaille/oidc/basemodels.py +++ b/canaille/oidc/basemodels.py @@ -8,8 +8,7 @@ from canaille.core.models import User class Client(Model): - """ - OpenID Connect client definition, based on the + """OpenID Connect client definition, based on the `OAuth 2.0 Dynamic Client Registration protocols `_ and the `OpenID Connect RP-Initiated Logout diff --git a/canaille/oidc/configuration.py b/canaille/oidc/configuration.py index d94cbfe7..9489c955 100644 --- a/canaille/oidc/configuration.py +++ b/canaille/oidc/configuration.py @@ -90,7 +90,8 @@ class OIDCSettings(BaseModel): """Wether a token is needed for the RFC7591 dynamical client registration. If :py:data:`True`, no token is needed to register a client. - If :py:data:`False`, dynamical client registration needs a token defined in :attr:`DYNAMIC_CLIENT_REGISTRATION_TOKENS`. + If :py:data:`False`, dynamical client registration needs a token defined in + :attr:`DYNAMIC_CLIENT_REGISTRATION_TOKENS`. """ DYNAMIC_CLIENT_REGISTRATION_TOKENS: Optional[List[str]] = None diff --git a/pyproject.toml b/pyproject.toml index aaf723fa..5f2adf70 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -179,7 +179,22 @@ exclude_lines = [ ] [tool.ruff.lint] -ignore = ["E501", "E722"] +select = [ + "E", # pycodestyle + "F", # pyflakes + "I", # isort + "UP", # pyupgrade +] +ignore = [ + "E501", # line-too-long + "E722", # bare-except +] + +[tool.ruff.lint.isort] +force-single-line = true + +[too.ruff.format] +docstring-code-format = true [tool.tox] legacy_tox_ini = """ diff --git a/tests/backends/ldap/test_object_class.py b/tests/backends/ldap/test_object_class.py index d9719430..84844c02 100644 --- a/tests/backends/ldap/test_object_class.py +++ b/tests/backends/ldap/test_object_class.py @@ -67,7 +67,6 @@ def test_keep_old_object_classes(backend, testclient, slapd_server): In such a case Canaille should keep the unmanaged objectClass and attributes. """ - user = models.User(cn="foo", sn="bar", user_name="baz") user.save() diff --git a/tests/core/test_forgotten_password.py b/tests/core/test_forgotten_password.py index fca293b0..5c2342d1 100644 --- a/tests/core/test_forgotten_password.py +++ b/tests/core/test_forgotten_password.py @@ -18,7 +18,8 @@ def test_password_forgotten(smtpd, testclient, user): res = res.form.submit(status=200) assert ( "success", - "A password reset link has been sent at your email address. You should receive it within a few minutes.", + "A password reset link has been sent at your email address. You should receive " + "it within a few minutes.", ) in res.flashes res.mustcontain("Send again") @@ -35,7 +36,8 @@ def test_password_forgotten_multiple_mails(smtpd, testclient, user): res = res.form.submit(status=200) assert ( "success", - "A password reset link has been sent at your email address. You should receive it within a few minutes.", + "A password reset link has been sent at your email address. You should receive " + "it within a few minutes.", ) in res.flashes res.mustcontain("Send again") @@ -61,7 +63,8 @@ def test_password_forgotten_invalid(smtpd, testclient, user): res = res.form.submit(status=200) assert ( "success", - "A password reset link has been sent at your email address. You should receive it within a few minutes.", + "A password reset link has been sent at your email address. " + "You should receive it within a few minutes.", ) in res.flashes res.mustcontain(no="The login 'i-dont-really-exist' does not exist") @@ -72,7 +75,8 @@ def test_password_forgotten_invalid(smtpd, testclient, user): res = res.form.submit(status=200) assert ( "success", - "A password reset link has been sent at your email address. You should receive it within a few minutes.", + "A password reset link has been sent at your email address. " + "You should receive it within a few minutes.", ) not in res.flashes res.mustcontain("The login 'i-dont-really-exist' does not exist") @@ -90,11 +94,13 @@ def test_password_forgotten_invalid_when_user_cannot_self_edit(smtpd, testclient res = res.form.submit(status=200) assert ( "success", - "A password reset link has been sent at your email address. You should receive it within a few minutes.", + "A password reset link has been sent at your email address. " + "You should receive it within a few minutes.", ) not in res.flashes assert ( "error", - "The user 'John (johnny) Doe' does not have permissions to update their password. We cannot send a password reset email.", + "The user 'John (johnny) Doe' does not have permissions to update their " + "password. We cannot send a password reset email.", ) in res.flashes testclient.app.config["CANAILLE"]["HIDE_INVALID_LOGINS"] = True @@ -105,11 +111,13 @@ def test_password_forgotten_invalid_when_user_cannot_self_edit(smtpd, testclient res = res.form.submit(status=200) assert ( "error", - "The user 'John (johnny) Doe' does not have permissions to update their password. We cannot send a password reset email.", + "The user 'John (johnny) Doe' does not have permissions to update their " + "password. We cannot send a password reset email.", ) not in res.flashes assert ( "success", - "A password reset link has been sent at your email address. You should receive it within a few minutes.", + "A password reset link has been sent at your email address. " + "You should receive it within a few minutes.", ) in res.flashes assert len(smtpd.messages) == 0 @@ -124,7 +132,8 @@ def test_password_forgotten_mail_error(SMTP, smtpd, testclient, user): res = res.form.submit(status=200, expect_errors=True) assert ( "success", - "A password reset link has been sent at your email address. You should receive it within a few minutes.", + "A password reset link has been sent at your email address. " + "You should receive it within a few minutes.", ) not in res.flashes assert ( "error",