Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
10 changes: 4 additions & 6 deletions .github/workflows/python.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v3
Expand All @@ -26,12 +26,10 @@ jobs:
python -m pip install --upgrade pip
pip install poetry
poetry install
- name: Lint with flake8
- name: Lint with ruff
run: |
# stop the build if there are Python syntax errors or undefined names
poetry run flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
poetry run flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
poetry run ruff check --select I pywaybiller --exclude pywaybiller/openapi_client
poetry run ruff check pywaybiller --exclude pywaybiller/openapi_client
- name: Test with pytest
run: |
poetry run pytest
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
# Changelog

## Unreleased
* **Breaking** Use refactored waybiller external API schema (exported via DRF-spectacular). Drop all previous schema
patches and start from scratch.

## Version 0.2.2
* Do not require organizer_user_id for creating transport orders, as it may not bre required if default is configured on the server

## Version 0.2.1
* Update Waybiller schema

## Version 0.2.0

* **Breaking** Use new Waybiller schema - some classes get renamed because of this change
* **Breaking** Drop support for Python 3.8
* Update to use newer openapi generator (pydantic 2)
* Ensure read-only fields are serialized correctly when saving data locally
* Fix set sanitization in sanitize_for_serialization

## Version 0.1.0

* Generate initial version of the client
Expand Down
21 changes: 12 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
OPENAPI_GENERATOR_VERSION ?= v7.0.1
API_HOST ?= app.waybiller.com
OPENAPI_GENERATOR_VERSION ?= v7.12.0
API_HOST ?= https://app.waybiller.com

.PHONY:
lint:
poetry run flake8 --select=E9,F63,F7,F82 pywaybiller
poetry run ruff check --select I pywaybiller --exclude pywaybiller/openapi_client
poetry run ruff check pywaybiller --exclude pywaybiller/openapi_client

.PHONY:
fmt:
poetry run black pywaybiller
poetry run black test
poetry run ruff check --select I pywaybiller --fix --exclude pywaybiller/openapi_client
poetry run ruff check pywaybiller --fix --exclude pywaybiller/openapi_client
poetry run ruff format pywaybiller --exclude pywaybiller/openapi_client

.PHONY:
test: ## run tests quickly with the default Python
test: # run tests quickly with the default Python
poetry run pytest

.PHONY:
test-all: ## run tests on every Python version with tox
test-all: # run tests on every Python version with tox
tox

.PHONY:
openapi-fetch:
curl https://$(API_HOST)/api/swagger/?format=openapi | poetry run python -c "import json; import sys; print(json.dumps(json.load(sys.stdin), indent=2))" > ./pywaybiller/openapi/waybiller_schema.json
curl $(API_HOST)/api/schema/ | poetry run python -c "import json; import sys; print(json.dumps(json.load(sys.stdin), indent=2))" > ./pywaybiller/openapi/waybiller_schema.json

.PHONY:
openapi-patch: openapi-fetch
Expand All @@ -40,7 +42,8 @@ openapi-build:
cp -r .openapi/openapi_client pywaybiller/openapi_client
cp -r .openapi/docs pywaybiller/docs
rm -rf .openapi
poetry run black pywaybiller
poetry run ruff check --select I pywaybiller/openapi_client --fix
poetry run ruff format pywaybiller/openapi_client

.PHONY:
openapi: openapi-apply-patch openapi-build
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ make docker-manage cmd="external_api_export --view waybill --endpoint list" > /t
poetry run python tests/manual_test_json_dump.py --filename /tmp/waybills-list.json --skip-lines 1 --model ExternalAPIWaybillList
```

To perform the manual test by direct API calls, use `manual_test_api.py`:
```shell
poetry run python tests/manual_test_api.py --model ExternalAPIWaybillList --api-key 'SECRET'
```

Note that you probably need to separately test list and detail endpoints, as schema is different.

This needs to be repeated for all endpoints you want to check. Currently, only waybill list and retrieve endpoints are
Expand Down
671 changes: 361 additions & 310 deletions poetry.lock

Large diffs are not rendered by default.

32 changes: 14 additions & 18 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,31 +1,27 @@
[tool.poetry]
[project]
name = "pywaybiller"
version = "0.1.0"
version = "1.0.0.dev0"
description = "Python client for waybiller.com external API"
authors = ["Thorgate <software@thorgate.eu>"]
authors = [{name = "Thorgate Digital", email = "software@thorgate.eu" }]
license = "MIT License"
readme = "README.md"
repository = "https://github.com/thorgate/pywaybiller.git"
keywords = ["OpenAPI", "OpenAPI-Generator", "pywaybiller"]
include = ["pywaybiller/py.typed"]

[tool.poetry.dependencies]
python = "^3.8"

urllib3 = ">= 1.25.3"
python-dateutil = ">=2.8.2"
pydantic = "^1.10.5, <2"
aenum = ">=3.1.11"
requires-python = ">=3.9,<4"
dependencies = [
"urllib3 (>= 1.25.3,< 3.0.0)",
"python-dateutil (>=2.8.2)",
"pydantic (>=2)",
"typing-extensions (>=4.7.1)"
]

[tool.poetry.group.dev.dependencies]
pytest = ">=7.2.1"
tox = ">=3.9.0"
flake8 = ">=4.0.0"
black = "^23.10.1"
json-stream = "^2.3.2"
ruff = "*"
pytest = "*"
tox = "*"
json-stream = "*"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"


32 changes: 29 additions & 3 deletions pywaybiller/client.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
# -*- coding: utf-8 -*-

"""Main module."""
import threading

import contextvars

from pydantic import BaseModel

from . import apis
from .openapi_client.api_client import ApiClient
from .openapi_client.configuration import Configuration

full_serialization = contextvars.ContextVar("full_serialization", default=False)


class ExtendedApiClient(ApiClient):
@classmethod
Expand All @@ -21,6 +26,27 @@ def deserialize_data(cls, response_data, response_type):
"""
return response_type.from_dict(response_data)

def sanitize_for_serialization(self, obj):
if hasattr(obj, "actual_instance"):
return self.sanitize_for_serialization(obj.actual_instance)

# For some reason, set sanitization is not handled correctly
if isinstance(obj, set):
obj = [*obj]

if full_serialization.get() and isinstance(obj, BaseModel):
return super().sanitize_for_serialization(obj.__dict__)

return super().sanitize_for_serialization(obj)

def serialize_fully(self, obj):
token = full_serialization.set(True)
try:
result = self.sanitize_for_serialization(obj)
finally:
full_serialization.reset(token)
return result


class WaybillerClient:
"""API client class for Waybiller.
Expand All @@ -32,7 +58,7 @@ class WaybillerClient:
openapi_client_class = ExtendedApiClient

def __init__(self, api_key: str, host: str = None):
configuration = Configuration(api_key={"API key": api_key})
configuration = Configuration(api_key={"ApiKeyAuth": api_key})
if host is not None:
configuration.host = host
self.openapi_client = self.openapi_client_class(configuration)
Expand All @@ -54,4 +80,4 @@ def deserialize_data(cls, response_data, response_type):

@classmethod
def sanitize_for_serialization(cls, api_model):
return cls.openapi_client_class().sanitize_for_serialization(api_model)
return cls.openapi_client_class().serialize_fully(api_model)
10 changes: 10 additions & 0 deletions pywaybiller/docs/BlankEnum.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# BlankEnum


## Enum

* `EMPTY` (value: `''`)

[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)


Loading