Skip to content
Draft
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
171 changes: 76 additions & 95 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,12 @@ authors = [{ name = "SoftwareOne AG" }]
requires-python = ">=3.12,<4"
readme = "README.md"
license = {text = "Apache-2.0 license"}

dependencies = [
"django==4.2.*",
"jinja2==3.1.*",
"markdown-it-py==3.0.*",
"mpt-extension-sdk==5.9.*",
"mpt-extension-sdk==5.15.*",
"requests==2.32.*",
]

Expand All @@ -19,6 +20,7 @@ app_config = "swo_playground.extension:ExtensionConfig"

[dependency-groups]
dev = [
"flake8>=7.3.0",
"freezegun==1.5.*",
"ipdb==0.13.*",
"ipython==9.*",
Expand All @@ -28,6 +30,7 @@ dev = [
"pytest-asyncio==1.1.*",
"pytest-cov==6.1.*",
"pytest-deadfixtures==2.2.*",
"pytest-django==4.8.*",
"pytest-mock==3.14.*",
"pytest-randomly==3.16.*",
"pytest-xdist==3.6.*",
Expand All @@ -48,15 +51,6 @@ runtime = [
"watchfiles==0.21.*",
]

[tool.uv]
default-groups = [
"dev",
"runtime",
]
dev-dependencies = [
"django-stubs",
]

[tool.hatch.build.targets.sdist]
include = ["swo_playground"]

Expand All @@ -70,7 +64,7 @@ build-backend = "hatchling.build"
[tool.pytest.ini_options]
testpaths = "tests"
pythonpath = "."
addopts = "--cov=swo_playground --cov-report=term-missing --cov-report=html --cov-report=xml --import-mode=importlib"
addopts = "--cov=mpt_extension_sdk --cov-report=term-missing --cov-report=html --cov-report=xml --import-mode=importlib"
DJANGO_SETTINGS_MODULE = "tests.django.settings"
log_cli = false
filterwarnings = [
Expand All @@ -79,85 +73,89 @@ filterwarnings = [
]

[tool.coverage.run]
relative_files = true
branch = true
relative_files = true
omit = [
"django.py",
"__init__.py",
"tests/**",
"swo_playground/default.py",
]

[tool.ruff]
# Ruff config: https://docs.astral.sh/ruff/settings
preview = true
target-version = "py312"
extend-exclude = [".vscode", ".devcontainer", "swo"]
extend-exclude=[".vscode", ".devcontainer"]
output-format = "full"
line-length = 100

[tool.ruff.format]
quote-style = "double"
# This is only required because we have invalid on-purpose code in docstrings:
docstring-code-format = false

[tool.ruff.lint]
select = [
"A", # flake8-builtins
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"C90", # maccabe
"COM", # flake8-commas
"D", # pydocstyle
"DTZ", # flake8-datetimez
"E", # pycodestyle
"ERA", # flake8-eradicate
"EXE", # flake8-executable
"F", # pyflakes
"FBT", # flake8-boolean-trap
"FLY", # pyflint
"FURB", # refurb
"G", # flake8-logging-format
"I", # isort
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"N", # pep8-naming
"PERF", # perflint
"PIE", # flake8-pie
"PL", # pylint
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"Q", # flake8-quotes
"RET", # flake8-return
"RSE", # flake8-raise
"RUF", # ruff
"S", # flake8-bandit
"SIM", # flake8-simpify
"SLF", # flake8-self
"SLOT", # flake8-slots
"T100", # flake8-debugger
"TRY", # tryceratops
"UP", # pyupgrade
"W", # pycodestyle
"YTT", # flake8-2020
"A", # flake8-builtins
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"C90", # maccabe
"COM", # flake8-commas
"D", # pydocstyle
"DTZ", # flake8-datetimez
"E", # pycodestyle
"ERA", # flake8-eradicate
"EXE", # flake8-executable
"F", # pyflakes
"FBT", # flake8-boolean-trap
"FLY", # pyflint
"FURB", # refurb
"G", # flake8-logging-format
"I", # isort
"ICN", # flake8-import-conventions
"ISC", # flake8-implicit-str-concat
"LOG", # flake8-logging
"N", # pep8-naming
"PERF", # perflint
"PIE", # flake8-pie
"PL", # pylint
"PT", # flake8-pytest-style
"PTH", # flake8-use-pathlib
"Q", # flake8-quotes
"RET", # flake8-return
"RSE", # flake8-raise
"RUF", # ruff
"S", # flake8-bandit
"SIM", # flake8-simpify
"SLF", # flake8-self
"SLOT", # flake8-slots
"T100", # flake8-debugger
"TRY", # tryceratops
"UP", # pyupgrade
"W", # pycodestyle
"YTT", # flake8-2020
]
ignore = [
"A005", # allow to shadow stdlib and builtin module names
"B904", # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling
"COM812", # trailing comma, conflicts with `ruff format`
# Different doc rules that we don't really care about:
"D100",
"D104",
"D105", # docstring for magic methods
"D106",
"D107",
"D203",
"D212",
"D401",
"D404",
"D405",
"ISC001", # implicit string concat conflicts with `ruff format`
"ISC003", # prefer explicit string concat over implicit concat
"PLR09", # we have our own complexity rules
"PLR2004", # do not report magic numbers
"PLR6301", # do not require classmethod / staticmethod when self not used
"PT011", # pytest.raises({exception}) is too broad, set the match parameter or use a more specific exception
"TRY003", # long exception messages from `tryceratops`
"A005", # allow to shadow stdlib and builtin module names
"B904", # Within an `except` clause, raise exceptions with `raise ... from err` or `raise ... from None` to distinguish them from errors in exception handling
"COM812", # trailing comma, conflicts with `ruff format`
# Different doc rules that we don't really care about:
"D100",
"D104",
"D105", # docstring for magic methods
"D106",
"D107",
"D203",
"D212",
"D401",
"D404",
"D405",
"ISC001", # implicit string concat conflicts with `ruff format`
"ISC003", # prefer explicit string concat over implicit concat
"PLR09", # we have our own complexity rules
"PLR2004", # do not report magic numbers
"PLR6301", # do not require classmethod / staticmethod when self not used
"PT011", # pytest.raises({exception}) is too broad, set the match parameter or use a more specific exception
"TRY003", # long exception messages from `tryceratops`
]
external = [ "WPS" ]

Expand All @@ -177,32 +175,15 @@ pydocstyle.convention = "google"
"S603", # do not require `shell=True`
"S607", # partial executable paths
]
"mpt_extension_sdk/swo_rql/query_builder.py" = [
"PLW2901", # loop variable overwritten by assignment target
]

[tool.ruff.lint.isort]
known-third-party = ["swo"]

[tool.mypy]
# The mypy configurations: http://bit.ly/2zEl9WI
ignore_missing_imports = true
strict = true
local_partial_types = true
warn_unreachable = true

enable_error_code = [
"truthy-bool",
"truthy-iterable",
"redundant-expr",
"unused-awaitable",
"ignore-without-code",
"possibly-undefined",
"redundant-self",
"explicit-override",
"mutable-override",
"unimported-reveal",
"deprecated",
]

exclude = ["tests"]
warn_no_return = false

[[tool.mypy.overrides]]
module = "django.*"
Expand Down
10 changes: 7 additions & 3 deletions setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ extend-exclude =
# We only run `wemake-python-styleguide` with `flake8`:
select = WPS, E999

extend-ignore =
# Found string constant over-use
WPS226

per-file-ignores =
__init__.py: WPS410 WPS412
tests/**/*.py: WPS202, WPS211, WPS226
tests/django/settings.py: WPS226 WPS407
swo_playground/default.py: WPS407 WPS111
swo_playground/__init__.py: WPS410 WPS412
tests/django/settings.py: WPS407
4 changes: 0 additions & 4 deletions swo_playground/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +0,0 @@
from swo_playground import api, events
from swo_playground.extension import ExtensionConfig

__all__ = ["ExtensionConfig", "api", "events"]
44 changes: 35 additions & 9 deletions swo_playground/api.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import logging
from collections.abc import Mapping
from pprint import pformat
from typing import Annotated, Any, Literal

from collection.abc import Mapping
from django.conf import settings
from django.http import HttpRequest
from mpt_extension_sdk.core.security import JWTAuth
from mpt_extension_sdk.flows.context import Context
from mpt_extension_sdk.mpt_http.base import MPTClient
from mpt_extension_sdk.mpt_http.mpt import get_webhook
from mpt_extension_sdk.runtime.djapp.conf import get_for_product
from mpt_extension_sdk.core.extension import Extension # type: ignore[import-untyped]
from mpt_extension_sdk.core.security import JWTAuth # type: ignore[import-untyped]
from mpt_extension_sdk.flows.context import Context # type: ignore[import-untyped]
from mpt_extension_sdk.mpt_http.base import MPTClient # type: ignore[import-untyped]
from mpt_extension_sdk.mpt_http.mpt import get_webhook # type: ignore[import-untyped]
from mpt_extension_sdk.runtime.djapp.conf import get_for_product # type: ignore[import-untyped]
from ninja import Body, Schema

from swo_playground.extension import ext

logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

ext = Extension()


class Error(Schema):
"""MPT API error message."""
Expand All @@ -43,6 +44,31 @@ def jwt_secret_callback(client: MPTClient, claims: Mapping[str, Any]) -> str:
return str(get_for_product(settings, "WEBHOOKS_SECRETS", product_id))


@ext.api.get(
"/",
description="Root endpoint.",
response={
200: dict,
400: Error,
},
) # type: ignore[misc]
def root(request: ExtensionHttpRequest) -> Response:
"""Root endpoint."""
return 200, {"message": "Ok"}


@ext.api.get(
"/healthcheck",
description="Healthcheck endpoint.",
response={
200: dict,
},
) # type: ignore[misc]
def healthcheck(request: ExtensionHttpRequest) -> Response:
"""Returns 200 healthy."""
return 200, {"status": "Healthy"}


@ext.api.post(
"/v1/orders/validate",
response={
Expand All @@ -62,7 +88,7 @@ def process_order_validation(
except Exception as exc:
logger.exception("Unexpected error during validation")
return 400, Error(
id="AWS001",
id="MPT001",
message=f"Unexpected error during validation: {exc}.",
)
else:
Expand Down
Loading