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

HP-2082 | Update Graphene, Django and Python #467

Merged
merged 16 commits into from
Feb 6, 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
26 changes: 12 additions & 14 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,18 @@ on:
branches: [develop, master]
pull_request:


env:
SECRET_KEY: topsecret123
FIELD_ENCRYPTION_KEYS: f164ec6bd6fbc4aef5647abc15199da0f9badcc1d2127bde2087ae0d794a9a0b


jobs:
test:
name: Tests
runs-on: ubuntu-latest

services:
postgres:
image: postgis/postgis:9.6-2.5
image: postgis/postgis:13-3.2
ports:
- 5432:5432
options: >-
Expand All @@ -33,15 +31,15 @@ jobs:

steps:
- name: Check out repository
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Set up Python 3.7
uses: actions/setup-python@v2
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.7'
python-version: '3.11'

- name: Cache pip packages
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: cache-pip-modules
with:
Expand Down Expand Up @@ -74,15 +72,15 @@ jobs:

steps:
- name: Check out repository
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Set up Python 3.7
uses: actions/setup-python@v2
- name: Set up Python 3.11
uses: actions/setup-python@v5
with:
python-version: '3.7'
python-version: '3.11'

- name: Cache pip packages
uses: actions/cache@v2
uses: actions/cache@v4
env:
cache-name: cache-pip-modules
with:
Expand All @@ -99,7 +97,7 @@ jobs:
run: flake8

- name: Import sorting
run: isort -c
run: isort . --check --diff

- name: Formatting
run: black --check .
4 changes: 2 additions & 2 deletions .github/workflows/review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
name: Build
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Build
uses: andersinno/kolga-build-action@v2

Expand All @@ -35,7 +35,7 @@ jobs:
needs: build
name: Review
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: andersinno/kolga-setup-action@v2

- name: Review-Services
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
name: Build
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- name: Build
uses: andersinno/kolga-build-action@v2

Expand All @@ -36,7 +36,7 @@ jobs:
needs: build
name: Staging
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: andersinno/kolga-setup-action@v2

- name: Deploy
Expand Down
18 changes: 13 additions & 5 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
default_language_version:
python: python3
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-added-large-files
- repo: https://github.com/psf/black
rev: 19.10b0
rev: 24.1.1
hooks:
- id: black
exclude: "snapshots"
- repo: https://gitlab.com/pycqa/flake8
rev: 3.7.9
- repo: https://github.com/pycqa/flake8
rev: 7.0.0
hooks:
- id: flake8
exclude: "migrations|snapshots"
additional_dependencies: ["pep8-naming"]
- repo: https://github.com/timothycrosley/isort
rev: 4.3.21
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
exclude: "migrations|snapshots"
41 changes: 24 additions & 17 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,53 +1,61 @@
# ==============================
FROM helsinkitest/python:3.7-slim as appbase
FROM python:3.11-slim-bookworm as appbase
# ==============================

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

WORKDIR /app
RUN mkdir /entrypoint

COPY tools /tools
ENV PATH="/tools:${PATH}"

RUN groupadd -g 1000 appuser \
&& useradd -u 1000 -g appuser -ms /bin/bash appuser \
&& chown -R appuser:appuser /app

COPY --chown=appuser:appuser requirements*.txt /app/

RUN apt-install.sh \
git \
curl \
build-essential \
libpq-dev \
gdal-bin \
netcat-openbsd \
pkg-config \
python3-gdal \
postgresql-client \
&& pip install -U pip \
&& pip install --upgrade pip setuptools wheel \
&& pip install --no-cache-dir --no-deps -r /app/requirements.txt \
&& pip install --no-cache-dir -r /app/requirements-prod.txt \
&& apt-cleanup.sh build-essential pkg-config
&& apt-cleanup.sh build-essential

COPY --chown=appuser:appuser docker-entrypoint.sh /entrypoint/docker-entrypoint.sh
ENTRYPOINT ["/entrypoint/docker-entrypoint.sh"]

# ==============================
FROM appbase as staticbuilder
# ==============================

ENV VAR_ROOT /app
COPY --chown=appuser:appuser . /app
RUN python manage.py collectstatic --noinput

# ==============================
FROM appbase as development
# ==============================

COPY --chown=appuser:appuser requirements-dev.txt /app/requirements-dev.txt
RUN pip install --no-cache-dir -r /app/requirements-dev.txt
RUN apt-install.sh build-essential \
&& pip install --no-cache-dir -r /app/requirements-dev.txt \
&& apt-cleanup.sh build-essential

ENV DEV_SERVER=1

COPY --chown=appuser:appuser . /app/

USER appuser

EXPOSE 8080/tcp

# ==============================
FROM appbase as staticbuilder
# ==============================

ENV VAR_ROOT /app
COPY --chown=appuser:appuser . /app
RUN python manage.py collectstatic --noinput

# ==============================
FROM appbase as production
# ==============================
Expand All @@ -56,5 +64,4 @@ COPY --from=staticbuilder --chown=appuser:appuser /app/static /app/static
COPY --chown=appuser:appuser . /app/

USER appuser

EXPOSE 8080/tcp
3 changes: 1 addition & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '3.7'
services:
postgres:
image: helsinkitest/postgis:9.6-2.5-alpine
image: postgis/postgis:13-3.2-alpine
restart: on-failure
environment:
POSTGRES_USER: open_city_profile
Expand Down Expand Up @@ -36,7 +36,6 @@ volumes:
driver: local
django-media-volume:


networks:
default:
name: helsinki
4 changes: 2 additions & 2 deletions open_city_profile/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from django.core.exceptions import PermissionDenied
from django.utils.translation import gettext_lazy as _
from graphql.execution.base import ResolveInfo
from graphql.type import GraphQLResolveInfo

from open_city_profile.exceptions import ServiceNotIdentifiedError

Expand All @@ -13,7 +13,7 @@ def decorator(decorator_function):
def wrapper(function):
@wraps(function)
def context_tester(*args, **kwargs):
info = next(arg for arg in args if isinstance(arg, ResolveInfo))
info = next(arg for arg in args if isinstance(arg, GraphQLResolveInfo))
context = info.context

for test_func in test_funcs:
Expand Down
36 changes: 18 additions & 18 deletions open_city_profile/graphene.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
from graphene_django import DjangoObjectType
from graphene_django.forms.converter import convert_form_field
from graphene_django.types import ALL_FIELDS
from graphql_sync_dataloaders import SyncDataLoader
from parler.models import TranslatableModel

from profiles.loaders import (
AddressesByProfileIdLoader,
EmailsByProfileIdLoader,
PhonesByProfileIdLoader,
PrimaryAddressForProfileLoader,
PrimaryEmailForProfileLoader,
PrimaryPhoneForProfileLoader,
addresses_by_profile_id_loader,
emails_by_profile_id_loader,
phones_by_profile_id_loader,
primary_address_for_profile_loader,
primary_email_for_profile_loader,
primary_phone_for_profile_loader,
)


Expand Down Expand Up @@ -52,12 +53,12 @@ class UUIDMultipleChoiceFilter(MultipleChoiceFilter):


_LOADERS = {
"addresses_by_profile_id_loader": AddressesByProfileIdLoader,
"emails_by_profile_id_loader": EmailsByProfileIdLoader,
"phones_by_profile_id_loader": PhonesByProfileIdLoader,
"primary_address_for_profile_loader": PrimaryAddressForProfileLoader,
"primary_email_for_profile_loader": PrimaryEmailForProfileLoader,
"primary_phone_for_profile_loader": PrimaryPhoneForProfileLoader,
"addresses_by_profile_id_loader": addresses_by_profile_id_loader,
"emails_by_profile_id_loader": emails_by_profile_id_loader,
"phones_by_profile_id_loader": phones_by_profile_id_loader,
"primary_address_for_profile_loader": primary_address_for_profile_loader,
"primary_email_for_profile_loader": primary_email_for_profile_loader,
"primary_phone_for_profile_loader": primary_phone_for_profile_loader,
}


Expand All @@ -69,17 +70,16 @@ def resolve(self, next, root, info, **kwargs):
context = info.context

if not self.cached_loaders:
for loader_name, loader_class in _LOADERS.items():
setattr(context, loader_name, loader_class())

for loader_name, loader_function in _LOADERS.items():
setattr(context, loader_name, SyncDataLoader(loader_function))
self.cached_loaders = True

return next(root, info, **kwargs)


def _parler_field_resolver(attname, instance, info, language=None):
if language:
return instance.safe_translation_getter(attname, language_code=language)
return instance.safe_translation_getter(attname, language_code=language.value)

return getattr(instance, attname)

Expand Down Expand Up @@ -151,7 +151,7 @@ def __init_subclass_with_meta__(
interfaces=(),
convert_choices_to_enum=True,
_meta=None,
**options
**options,
):
assert issubclass(model, TranslatableModel), (
'You need to pass a valid Django Parler Model in {}.Meta, received "{}".'
Expand All @@ -176,5 +176,5 @@ def __init_subclass_with_meta__(
interfaces=interfaces,
convert_choices_to_enum=convert_choices_to_enum,
_meta=_meta,
**options
**options,
)
19 changes: 14 additions & 5 deletions open_city_profile/tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
from graphene.test import Client as GrapheneClient
from graphene_django.settings import graphene_settings
from graphene_django.views import instantiate_middleware
from graphql import build_client_schema, introspection_query
from graphql import build_client_schema, get_introspection_query
from graphql_sync_dataloaders import DeferredExecutionContext
from helusers.authz import UserAuthorization

from open_city_profile.schema import schema
Expand All @@ -33,7 +34,7 @@ def execute(
auth_token_payload=None,
service=_not_provided,
context=None,
**kwargs
**kwargs,
):
"""
Custom execute method which adds all of the middlewares defined in the
Expand Down Expand Up @@ -70,7 +71,7 @@ def execute(
*args,
context=context,
middleware=list(instantiate_middleware(graphene_settings.MIDDLEWARE)),
**kwargs
**kwargs,
)


Expand Down Expand Up @@ -127,6 +128,11 @@ def keycloak_setup(settings):
settings.KEYCLOAK_CLIENT_SECRET = "test-keycloak-client-secret"


@pytest.fixture
def execution_context_class():
return DeferredExecutionContext


@pytest.fixture
def user():
return UserFactory()
Expand Down Expand Up @@ -178,8 +184,11 @@ def superuser_gql_client():


@pytest.fixture
def gql_schema(anon_user_gql_client):
introspection = anon_user_gql_client.execute(introspection_query)
def gql_schema(anon_user_gql_client, execution_context_class):
introspection = anon_user_gql_client.execute(
get_introspection_query(descriptions=False),
execution_context_class=execution_context_class,
)
return build_client_schema(introspection["data"])


Expand Down
Loading