Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Python deps & use ruff for linting/formatting #485

Merged
merged 6 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ['3.9', '3.10', '3.11', '3.12']
python-version: ['3.12']

services:
postgres:
Expand All @@ -23,15 +23,15 @@ jobs:
options: --health-cmd pg_isready --health-interval 5s --health-timeout 5s --health-retries 10

steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4

- name: Setup Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 16.x

Expand Down Expand Up @@ -60,4 +60,4 @@ jobs:

- name: Lint
if: matrix.python-version == 3.12
run: make lint
run: make lint-ci
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ __pycache__/
*.whl
build/
.cache/
.ruff_cache/
pip-wheel-metadata/

# Tests
Expand Down
9 changes: 0 additions & 9 deletions .isort.cfg

This file was deleted.

17 changes: 12 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -94,19 +94,26 @@ react-server: i18n
.PHONY: lint
lint:
@printf " \033[38;5;154mDEV\033[0m \033[38;5;77mLinting code\033[0m\n"
@npm run flake8
@npm run ruff
@npm run eslint:check
@npm run prettier:check
@npm run isort:check
@npm run black:check
@npm run ruff-format:check


.PHONY: lint-ci
lint-ci:
@printf " \033[38;5;154mDEV\033[0m \033[38;5;77mLinting code (CI)\033[0m\n"
@npm run ruff -- --output-format github
@npm run eslint:check
@npm run prettier:check
@npm run ruff-format:check


.PHONY: format
format:
@printf " \033[38;5;154mDEV\033[0m \033[38;5;77mFormatting code\033[0m\n"
@npm run eslint
@npm run isort
@npm run black
@npm run ruff-format


.PHONY: test
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ decided (still work in progress!).

## Development

We chose Python 3.12 as the backend language, so make sure you have it installed (3.9-3.11 should work as well). To prepare the development environment it is enough to run `make` which takes care of installing all required dependencies inside a new virtualenv. Typically that will be the `.venv` directory unless you override the environment variable `VENV` *e.g.* `VENV=.virtualenv make`. Activate your virtualenv using ``source .venv/bin/activate`` since this is required to run the various `flask` comments that come later.
We chose Python 3.12 as the backend language, so make sure you have it installed (`pyenv` helps if your distribution does not include it). To prepare the development environment it is enough to run `make` which takes care of installing all required dependencies inside a new virtualenv. Typically that will be the `.venv` directory unless you override the environment variable `VENV` *e.g.* `VENV=.virtualenv make`. Activate your virtualenv using ``source .venv/bin/activate`` since this is required to run the various `flask` comments that come later.

Make sure you have the `python` binary in your PATH. You can also use the `PYTHON` environment variable to override the location of the
`python` binary. *e.g.:*
Expand Down Expand Up @@ -64,7 +64,7 @@ We provide a couple of additional `make` targets that should streamline the deve
- `make clean` - removes all generated files
- `make distclean` - runs `clean` target first and removes config files afterwards
- `make lint` - runs linters, which report possible code style issues
- `make format` - runs code formatters over the entire codebase (black, isort, prettier)
- `make format` - runs code formatters over the entire codebase (ruff, prettier)
- `make test` - runs Python and React tests
- `make build` - builds a Python wheel which then could be used to install `newdle` in production

Expand Down
3 changes: 2 additions & 1 deletion ci/check_history_consistency.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Checks the consistency of the history, by comparing flask db
output and the filesystem ordering of files.
"""

import re
import subprocess
import sys
Expand Down Expand Up @@ -37,7 +38,7 @@ def _check_history_consistency():
if revisions != file_revisions:
print(
'::error::'
'The order of revisions in the database and in the filesystem is different. '
'The order of revisions in the database and filesystem is different. '
'Please review them and make sure the revision history is linear. '
'Make sure that all the migrations have a distinct "down_revision".'
)
Expand Down
9 changes: 4 additions & 5 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
from newdle.core.db import db
from newdle.models import Newdle, Participant


TEST_DATABASE_URI = os.environ.get(
'NEWDLE_TEST_DATABASE_URI', 'postgresql:///newdle_tests'
)
Expand Down Expand Up @@ -39,13 +38,13 @@ def database(app):
flask_migrate.downgrade(revision='base')


@pytest.fixture()
@pytest.fixture
def db_session(app, database):
"""Create a new database session."""
connection = db.engine.connect()
transaction = connection.begin()

options = dict(bind=connection, binds={})
options = {'bind': connection, 'binds': {}}
session_factory = sessionmaker(**options)
session = scoped_session(session_factory)

Expand All @@ -67,7 +66,7 @@ def mail_queue():
return django_mail.outbox


@pytest.fixture()
@pytest.fixture
def flask_client(app):
return app.test_client()

Expand All @@ -89,7 +88,7 @@ def dummy_participant_uid():

@pytest.fixture
def create_newdle(dummy_uid, db_session):
"""Return a callable which lets you create dummy newdles"""
"""Return a callable which lets you create dummy newdles."""

def _create_newdle(id=None, **kwargs):
kwargs.setdefault(
Expand Down
23 changes: 11 additions & 12 deletions newdle/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@
from sqlalchemy.orm import selectinload
from werkzeug.exceptions import Forbidden, ServiceUnavailable, UnprocessableEntity

from .answers import validate_answers
from .calendar import create_calendar_event
from .core.auth import search_users, user_info_from_app_token
from .core.db import db
from .core.util import (
from newdle.answers import validate_answers
from newdle.calendar import create_calendar_event
from newdle.core.auth import search_users, user_info_from_app_token
from newdle.core.db import db
from newdle.core.util import (
DATE_FORMAT,
avatar_info_from_payload,
change_dt_timezone,
range_union,
render_user_avatar,
)
from .core.webargs import abort, use_args, use_kwargs
from .export import export_answers_to_csv, export_answers_to_xlsx
from .models import Availability, Newdle, Participant, StatKey, Stats
from .notifications import (
from newdle.core.webargs import abort, use_args, use_kwargs
from newdle.export import export_answers_to_csv, export_answers_to_xlsx
from newdle.models import Availability, Newdle, Participant, StatKey, Stats
from newdle.notifications import (
notify_newdle_creator,
notify_newdle_participants,
send_invitation_emails,
)
from .schemas import (
from newdle.schemas import (
DeletedNewdleSchema,
MyNewdleSchema,
NewdleParticipantSchema,
Expand All @@ -57,7 +57,6 @@
UserSearchResultSchema,
)


api = Blueprint('api', __name__, url_prefix='/api')


Expand Down Expand Up @@ -616,7 +615,7 @@ def send_deletion_emails(args, code):
'title': newdle.title,
'participant': p.name,
'summary_link': url_for('newdle_summary', code=newdle.code, _external=True),
'comment': args['comment'] if 'comment' in args else None,
'comment': args.get('comment'),
},
)
return '', 204
Expand Down
3 changes: 1 addition & 2 deletions newdle/auth.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from flask import Blueprint, current_app, redirect, render_template, session, url_for

from .core.auth import app_token_from_dummy, multipass

from newdle.core.auth import app_token_from_dummy, multipass

auth = Blueprint('auth', __name__)

Expand Down
6 changes: 3 additions & 3 deletions newdle/calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ def _email_to_vcal_address(email):


def _add_participant_to_ical_event(event, participant):
"""Adds a participant as an attendee to an ical event."""
"""Add a participant as an attendee to an ical event."""
attendee = _email_to_vcal_address(participant.email)
attendee.params['cn'] = vText(participant.name)
attendee.params['ROLE'] = vText('REQ-PARTICIPANT')
Expand Down Expand Up @@ -47,8 +47,8 @@ def create_calendar_event(newdle, participant=None):

if not newdle.private and not participant:
participants = [p for p in newdle.participants if p.email]
for participant in participants:
_add_participant_to_ical_event(event, participant)
for part in participants:
_add_participant_to_ical_event(event, part)

calendar.add_component(event)
return calendar.to_ical()
11 changes: 7 additions & 4 deletions newdle/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
from flask import Blueprint, current_app
from sqlalchemy import and_, or_

from .core.db import db
from .models import Newdle
from .providers.free_busy.util import get_msal_app, get_msal_token, save_msal_cache

from newdle.core.db import db
from newdle.models import Newdle
from newdle.providers.free_busy.util import (
get_msal_app,
get_msal_token,
save_msal_cache,
)

try:
import exchangelib
Expand Down
18 changes: 9 additions & 9 deletions newdle/core/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
from werkzeug.exceptions import HTTPException
from werkzeug.middleware.proxy_fix import ProxyFix

from ..api import api
from ..auth import auth
from ..cli import cli
from .auth import multipass
from .cache import cache
from .db import db, migrate
from .marshmallow import mm
from .util import dedent
from newdle.api import api
from newdle.auth import auth
from newdle.cli import cli
from newdle.core.auth import multipass
from newdle.core.cache import cache
from newdle.core.db import db, migrate
from newdle.core.marshmallow import mm
from newdle.core.util import dedent


def _configure_app(app, from_env=True):
Expand Down Expand Up @@ -76,7 +76,7 @@ def _handle_exception(exc):
# If the client prefers HTML (probably a browser), we keep the
# default logic which results in standard "internal server error"
# message or the debugger while in development mode.
raise
raise # noqa: PLE0704
app.logger.exception('Request failed')
return jsonify(error='internal_error'), 500

Expand Down
2 changes: 1 addition & 1 deletion newdle/core/auth.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from flask import current_app, render_template
from flask_multipass import Multipass

from .util import secure_timed_serializer
from newdle.core.util import secure_timed_serializer


class NewdleMultipass(Multipass):
Expand Down
1 change: 0 additions & 1 deletion newdle/core/cache.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from flask_caching import Cache


cache = Cache(with_jinja2_ext=False)
1 change: 0 additions & 1 deletion newdle/core/marshmallow.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from flask_marshmallow import Marshmallow


mm = Marshmallow()
2 changes: 1 addition & 1 deletion newdle/core/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
from itsdangerous import BadData, Signer, URLSafeSerializer, URLSafeTimedSerializer
from werkzeug.local import LocalProxy


DATE_FORMAT = '%Y-%m-%d'
DATETIME_FORMAT = '%Y-%m-%dT%H:%M'

Expand All @@ -21,6 +20,7 @@


class AutoNameEnum(Enum):
@staticmethod
def _generate_next_value_(name, start, count, last_values):
return name

Expand Down
6 changes: 3 additions & 3 deletions newdle/core/webargs.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ def pre_load(self, location_data, *, schema, req, location):
def handle_error(error, req, schema, *, error_status_code, error_headers):
# since 6.0.0b7 errors are namespaced by their source. this is nice for APIs taking
# data from different locations to serve very specific errors, but in a typical web
# app where you usually have only one source and certainly not the same field name in
# different locations, it just makes handling errors in JS harder since we suddenly
# have to care if it's form data or json data
# app where you usually have only one source and certainly not the same field name
# in different locations, it just makes handling errors in JS harder since we
# suddenly have to care if it's form data or json data
namespaced = error.messages # mutating this below is safe
error.messages = namespaced.popitem()[1]
assert not namespaced # we never expect to have more than one location
Expand Down
5 changes: 3 additions & 2 deletions newdle/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import datetime
from contextlib import contextmanager
from io import BytesIO, TextIOWrapper
from operator import itemgetter

from xlsxwriter import Workbook

Expand All @@ -11,7 +12,7 @@
def _generate_answers_for_export(newdle):
slots = [format_dt(slot) for slot in newdle.timeslots]
rows = []
rows.append(['Participant name'] + slots + ['Comment'])
rows.append(['Participant name', *slots, 'Comment'])

for p in newdle.participants:
answers = [p.name]
Expand All @@ -23,7 +24,7 @@ def _generate_answers_for_export(newdle):
answers.append(p.comment)
rows.append(answers)
# Sort participants by name
rows[1:] = sorted(rows[1:], key=lambda row: row[0])
rows[1:] = sorted(rows[1:], key=itemgetter(0))
return rows


Expand Down
1 change: 0 additions & 1 deletion newdle/migrations/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
from flask import current_app
from sqlalchemy import engine_from_config, pool


# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
from alembic import op
from sqlalchemy.dialects import postgresql


# revision identifiers, used by Alembic.
revision = '000000000000'
down_revision = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = '93a638b96375'
down_revision = '000000000000'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import sqlalchemy as sa
from alembic import op


# revision identifiers, used by Alembic.
revision = '679eab4aab01'
down_revision = '93a638b96375'
Expand Down
Loading
Loading