forked from Github-Mirrors/canaille
chore: configure ruff
This commit is contained in:
parent
256566df94
commit
dc89a20b11
13 changed files with 63 additions and 54 deletions
|
@ -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:
|
||||
|
|
|
@ -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 <flask:config>`
|
||||
- :doc:`Flask-WTF <flask-wtf:config>`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
<https://datatracker.ietf.org/doc/html/rfc7643#section-4.1>`_,
|
||||
`Entreprise User Schema Extension
|
||||
<https://datatracker.ietf.org/doc/html/rfc7643#section-4.3>`_
|
||||
|
@ -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
|
||||
<https://datatracker.ietf.org/doc/html/rfc7643#section-4.2>`_.
|
||||
"""
|
||||
|
||||
|
|
|
@ -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
|
||||
<https://datatracker.ietf.org/doc/html/rfc7591.html>`_
|
||||
and the `OpenID Connect RP-Initiated Logout
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = """
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in a new issue