From 446e6f166d406d8874cf51081f18f3a8c3a7fe9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= Date: Sun, 19 Jan 2025 00:14:15 +0000 Subject: [PATCH] chore: initial structure --- .github/workflows/deploy.yml | 28 ++++++++++ .github/workflows/main.yml | 56 +++++++++++++++++++ .gitignore | 15 +++++ .project | 18 ++++++ .pydevproject | 8 +++ .settings/org.eclipse.core.resources.prefs | 2 + CHANGELOG.md | 33 +++++++++++ README.md | 5 +- pytest.ini | 3 + requirements.txt | 1 + setup.cfg | 2 + setup.py | 47 ++++++++++++++++ src/colony_print/__init__.py | 6 ++ src/colony_print/base.py | 64 ++++++++++++++++++++++ src/colony_print/base.pyi | 58 ++++++++++++++++++++ src/colony_print/scripts/__init__.py | 6 ++ src/colony_print/scripts/sender.py | 37 +++++++++++++ src/colony_print/test/__init__.py | 26 +++++++++ src/colony_print/test/base.py | 10 ++++ src/examples/__init__.py | 8 +++ src/examples/app.py | 51 +++++++++++++++++ src/examples/base.py | 10 ++++ 22 files changed, 492 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/deploy.yml create mode 100644 .github/workflows/main.yml create mode 100644 .gitignore create mode 100644 .project create mode 100644 .pydevproject create mode 100644 .settings/org.eclipse.core.resources.prefs create mode 100644 CHANGELOG.md create mode 100644 pytest.ini create mode 100644 requirements.txt create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 src/colony_print/__init__.py create mode 100644 src/colony_print/base.py create mode 100644 src/colony_print/base.pyi create mode 100644 src/colony_print/scripts/__init__.py create mode 100644 src/colony_print/scripts/sender.py create mode 100644 src/colony_print/test/__init__.py create mode 100644 src/colony_print/test/base.py create mode 100644 src/examples/__init__.py create mode 100644 src/examples/app.py create mode 100644 src/examples/base.py diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..1bf936e --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,28 @@ +name: Deploy Workflow +on: + push: + tags: + - "*" +jobs: + build: + name: Build + strategy: + matrix: + python-version: [2.7] + runs-on: ubuntu-latest + container: python:${{ matrix.python-version }} + steps: + - uses: actions/checkout@v4 + - run: python --version + - run: pip install -r requirements.txt + - run: | + pip install black + black . --check + if: matrix.python-version == '3.12' + - run: python setup.py test + - run: pip install twine wheel + - run: python setup.py sdist bdist_wheel + - run: python -m twine upload -u ${PYPI_USERNAME} -p ${PYPI_PASSWORD} dist/* + env: + PYPI_USERNAME: ${{ secrets.PYPI_USERNAME }} + PYPI_PASSWORD: ${{ secrets.PYPI_PASSWORD }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..ca4922d --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,56 @@ +name: Main Workflow +on: [push] +jobs: + build: + name: Build + strategy: + matrix: + python-version: [ + 2.7, + 3.5, + 3.6, + 3.7, + 3.8, + 3.9, + "3.10", + "3.11", + "3.12", + latest, + rc + ] + runs-on: ubuntu-latest + container: python:${{ matrix.python-version }} + steps: + - uses: actions/checkout@v4 + - run: python --version + - run: pip install -r requirements.txt + - run: | + pip install black + black . --check + if: matrix.python-version == '3.12' + - run: | + pip install pytest + pytest + - run: python setup.py test + if: matrix.python-version != '3.12' && matrix.python-version != 'latest' + + build-pypy: + name: Build PyPy + strategy: + matrix: + python-version: [2.7, 3.6, 3.9, "3.10"] + runs-on: ubuntu-latest + container: pypy:${{ matrix.python-version }} + steps: + - uses: actions/checkout@v4 + - run: pypy --version + - run: pip install -r requirements.txt + - run: | + pip install black + black . --check + if: matrix.python-version == '3.12' + - run: | + pip install pytest + pytest + - run: pypy setup.py test + if: matrix.python-version != '3.12' && matrix.python-version != 'latest' diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0aaaed9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +*.pyc +*.debug + +session.shelve* + +.DS_Store + +/.vscode/settings.json + +/.env +/.venv + +/dist +/build +/src/colony_print_api.egg-info diff --git a/.project b/.project new file mode 100644 index 0000000..611c452 --- /dev/null +++ b/.project @@ -0,0 +1,18 @@ + + + colony-print-api + + + appier + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 0000000..fe67e78 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,8 @@ + + + +/${PROJECT_DIR_NAME}/src + +Default +python 3.6 + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..998922f --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding/=utf-8 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..d6878b6 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,33 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +* + +### Changed + +* + +### Fixed + +* + +## [0.2.1] - 2024-04-30 + +### Changed + +* Direct inclusion of pyi files in `setup.py` + +## [0.2.0] - 2024-04-20 + +### Changed + +* Sanitization of the code structure, making compliant with `black` +* Improved support for type hints diff --git a/README.md b/README.md index 6d90a37..7b9fb33 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ -# colony-print-api -Python API client for Colony Print +# Colony Print API + +Python API client for Colony Print. diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..47766a4 --- /dev/null +++ b/pytest.ini @@ -0,0 +1,3 @@ +[pytest] +python_files = *.py +testpaths = src/colony_print/test diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..e8a5b90 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +appier diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..14536a5 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,2 @@ +[bdist_wheel] +universal = 1 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7745a13 --- /dev/null +++ b/setup.py @@ -0,0 +1,47 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import os +import setuptools + +setuptools.setup( + name="colony-print-api", + version="0.1.0", + author="Hive Solutions Lda.", + author_email="development@hive.pt", + description="Colony Print API Client", + license="Apache License, Version 2.0", + keywords="colony-print api", + url="http://colony-print-api.hive.pt", + zip_safe=False, + packages=["colony_print"], + test_suite="colony_print.test", + package_dir={"": os.path.normpath("src")}, + package_data={"colony_print": ["*.pyi"]}, + install_requires=["appier"], + classifiers=[ + "Development Status :: 3 - Alpha", + "Topic :: Utilities", + "License :: OSI Approved :: Apache Software License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.0", + "Programming Language :: Python :: 3.1", + "Programming Language :: Python :: 3.2", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + ], + long_description=open(os.path.join(os.path.dirname(__file__), "README.md"), "rb") + .read() + .decode("utf-8"), + long_description_content_type="text/markdown", +) diff --git a/src/colony_print/__init__.py b/src/colony_print/__init__.py new file mode 100644 index 0000000..9318819 --- /dev/null +++ b/src/colony_print/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from . import base + +from .base import BASE_URL, API, Attachment, AttachmentPayload, Message, MessagePayload diff --git a/src/colony_print/base.py b/src/colony_print/base.py new file mode 100644 index 0000000..2a3d099 --- /dev/null +++ b/src/colony_print/base.py @@ -0,0 +1,64 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import appier + +BASE_URL = "https://print.bemisc.com/api/" +""" The default base URL to be used when no other +base URL value is provided to the constructor """ + + +class API(appier.API): + """ + Implementation of the Colony Print API specification + for a simplified python client usage. + """ + + def __init__(self, *args, **kwargs): + appier.API.__init__(self, *args, **kwargs) + self.base_url = appier.conf("PRINT_BASE_URL", BASE_URL) + self.key = appier.conf("PRINT_KEY", None) + self.base_url = kwargs.get("base_url", self.base_url) + self.key = appier.conf("key", self.key) + + def build( + self, + method, + url, + data=None, + data_j=None, + data_m=None, + headers=None, + params=None, + mime=None, + kwargs=None, + ): + auth = kwargs.pop("auth", True) + if auth and self.key: + headers["X-Secret-Key"] = self.key + + def ping(self): + url = self.base_url + "ping" + contents = self.get(url, auth=False) + return contents + + def send(self, payload): + url = self.base_url + "send" + contents = self.post(url, data_j=payload) + return contents + + +class Attachment(dict): + pass + + +class AttachmentPayload(dict): + pass + + +class Message(dict): + pass + + +class MessagePayload(dict): + pass diff --git a/src/colony_print/base.pyi b/src/colony_print/base.pyi new file mode 100644 index 0000000..fa2d720 --- /dev/null +++ b/src/colony_print/base.pyi @@ -0,0 +1,58 @@ +from typing import NotRequired, Sequence, TypedDict +from appier import API as BaseAPI + +BASE_URL: str = ... + +class Attachment(TypedDict): + name: str + data: str + mime: str + hash: str + etag: str + guid: str + engine: str + +class AttachmentPayload(TypedDict): + name: str + data: str + mime: NotRequired[str] + hash: NotRequired[str] + etag: NotRequired[str] + guid: NotRequired[str] + engine: NotRequired[str] + +class Message(TypedDict): + sender: str | None + receivers: Sequence[str] + cc: Sequence[str] + bcc: Sequence[str] + reply_to: Sequence[str] + subject: str + title: str + subtitle: str | None + contents: str + html: str + plain: str + copyright: str + logo_url: str | None + attachments: Sequence[Attachment] + id: str | None + inline: bool + style: str + mode: str + +class MessagePayload(TypedDict): + receivers: Sequence[str] + subject: NotRequired[str] + title: NotRequired[str] + contents: NotRequired[str] + html: NotRequired[str] + plain: NotRequired[str] + copyright: NotRequired[str] + attachments: NotRequired[Sequence[AttachmentPayload]] + inline: NotRequired[bool] + style: NotRequired[str] + mode: NotRequired[str] + +class API(BaseAPI): + def send(self, payload: MessagePayload) -> Message: ... diff --git a/src/colony_print/scripts/__init__.py b/src/colony_print/scripts/__init__.py new file mode 100644 index 0000000..db35774 --- /dev/null +++ b/src/colony_print/scripts/__init__.py @@ -0,0 +1,6 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from . import sender + +from .sender import send diff --git a/src/colony_print/scripts/sender.py b/src/colony_print/scripts/sender.py new file mode 100644 index 0000000..bff14cf --- /dev/null +++ b/src/colony_print/scripts/sender.py @@ -0,0 +1,37 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import pprint + +import appier +import colony_print + + +def send(*args, **kwargs): + api = colony_print.API() + return api.send(kwargs) + + +if __name__ == "__main__": + receivers = appier.conf("RECEIVERS", [], cast=list) + subject = appier.conf("SUBJECT", None) + title = appier.conf("TITLE", None) + contents = appier.conf("CONTENTS", None) + copyright = appier.conf("COPYRIGHT", None) + + kwargs = dict() + if receivers: + kwargs["receivers"] = receivers + if subject: + kwargs["subject"] = subject + if title: + kwargs["title"] = title + if contents: + kwargs["contents"] = contents + if copyright: + kwargs["copyright"] = copyright + + result = send(**kwargs) + pprint.pprint(result) +else: + __path__ = [] diff --git a/src/colony_print/test/__init__.py b/src/colony_print/test/__init__.py new file mode 100644 index 0000000..c01a4ab --- /dev/null +++ b/src/colony_print/test/__init__.py @@ -0,0 +1,26 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Hive Dropbox API +# Copyright (c) 2008-2024 Hive Solutions Lda. +# +# This file is part of Hive Dropbox API. +# +# Hive Dropbox API is free software: you can redistribute it and/or modify +# it under the terms of the Apache License as published by the Apache +# Foundation, either version 2.0 of the License, or (at your option) any +# later version. +# +# Hive Dropbox API is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# Apache License for more details. +# +# You should have received a copy of the Apache License along with +# Hive Dropbox API. If not, see . + +__copyright__ = "Copyright (c) 2008-2024 Hive Solutions Lda." +""" The copyright for the module """ + +__license__ = "Apache License, Version 2.0" +""" The license for the module """ diff --git a/src/colony_print/test/base.py b/src/colony_print/test/base.py new file mode 100644 index 0000000..21d90f0 --- /dev/null +++ b/src/colony_print/test/base.py @@ -0,0 +1,10 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import unittest + + +class BaseTest(unittest.TestCase): + + def test_basic(self): + self.assertEqual(1 + 1, 2) diff --git a/src/examples/__init__.py b/src/examples/__init__.py new file mode 100644 index 0000000..aebdad4 --- /dev/null +++ b/src/examples/__init__.py @@ -0,0 +1,8 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +from . import app +from . import base + +from .app import ColonyPrintApp +from .base import get_api diff --git a/src/examples/app.py b/src/examples/app.py new file mode 100644 index 0000000..df76b25 --- /dev/null +++ b/src/examples/app.py @@ -0,0 +1,51 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import appier + +from . import base + + +class ColonyPrintApp(appier.WebApp): + + def __init__(self, *args, **kwargs): + appier.WebApp.__init__(self, name="colony_print", *args, **kwargs) + + @appier.route("/", "GET") + def index(self): + return self.ping() + + @appier.route("/ping", "GET") + def ping(self): + api = self.get_api() + result = api.ping() + return result + + @appier.route("/send", "GET") + def send(self): + receivers = self.field("receivers", [], cast=list) + subject = self.field("subject", "Test email") + title = self.field("title", "Test email") + contents = self.field("contents", "Test email") + copyright = self.field("copyright", "Hive Solutions") + payload = dict( + receivers=receivers, + subject=subject, + title=title, + contents=contents, + copyright=copyright, + ) + api = self.get_api() + result = api.send(payload) + return result + + def get_api(self): + api = base.get_api() + return api + + +if __name__ == "__main__": + app = ColonyPrintApp() + app.serve() +else: + __path__ = [] diff --git a/src/examples/base.py b/src/examples/base.py new file mode 100644 index 0000000..09ff094 --- /dev/null +++ b/src/examples/base.py @@ -0,0 +1,10 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +import appier + +import colony_print + + +def get_api(): + return colony_print.API(key=appier.conf("PRINT_KEY"))