From 53db74367afaf83122b36bcae2e94622a0e08978 Mon Sep 17 00:00:00 2001 From: George Melikov Date: Mon, 17 Feb 2025 12:26:48 +0300 Subject: [PATCH 1/4] Minor cleanups, black, requirement versions --- templates/py_dummy/setup.cfg | 4 +++- templates/py_dummy/test-requirements.txt | 7 +++--- templates/py_dummy/tox.ini | 30 ++++++++++++++---------- 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/templates/py_dummy/setup.cfg b/templates/py_dummy/setup.cfg index 3c65db3..8abe170 100644 --- a/templates/py_dummy/setup.cfg +++ b/templates/py_dummy/setup.cfg @@ -3,9 +3,10 @@ name = {{ project.name }} summary = {{ project.summary }} description_file = README.md +long_description_content_type = text/markdown author = {{ author.name }} author_email = {{ author.email }} -home_page = https://github.com/infraguys/{{ project.name}}/ +home_page = https://github.com/infraguys/{{ project.name }}/ classifier = Intended Audience :: Developers License :: OSI Approved :: Apache Software License @@ -16,6 +17,7 @@ classifier = Programming Language :: Python :: 3.10 Programming Language :: Python :: 3.11 Programming Language :: Python :: 3.12 + Programming Language :: Python :: 3.13 [files] packages = diff --git a/templates/py_dummy/test-requirements.txt b/templates/py_dummy/test-requirements.txt index a6ef082..25cc89b 100644 --- a/templates/py_dummy/test-requirements.txt +++ b/templates/py_dummy/test-requirements.txt @@ -1,5 +1,4 @@ -coverage>=4.0 -flake8>=6.1.0 # MIT License (MIT) +coverage>=4.0 # Apache-2.0 mock>=3.0.5,<4.0.0 # BSD -pytest==7.0.1,<8.0.0 # MIT License (MIT) -pytest-timer==0.0.11 # MIT License (MIT) +pytest>=8.0.0,<9.0.0 # MIT License (MIT) +pytest-timer>=1.0.0,<2.0.0 # MIT License (MIT) diff --git a/templates/py_dummy/tox.ini b/templates/py_dummy/tox.ini index 645461c..0788252 100644 --- a/templates/py_dummy/tox.ini +++ b/templates/py_dummy/tox.ini @@ -1,12 +1,14 @@ [tox] -envlist = py3{8,10,11,12},pep8 +envlist = black,py3{8,10,11,12,13},py3{8,10,12,13}-functional [testenv] deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt setenv = - TEST_PATH={{ project.package_name }}/tests + PACKAGE_NAME={{ project.package_name }} + TEST_PATH={env:PACKAGE_NAME}/tests + functional: TEST_PATH={env:PACKAGE_NAME}/tests/functional commands = coverage run -p -m pytest {posargs} --timer-top-n=10 {env:TEST_PATH} @@ -26,22 +28,15 @@ deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = coverage erase - coverage run -m pytest {posargs} --timer-top-n=10 {{ project.package_name }}/tests - coverage report --omit=.tox/*,{{ project.package_name }}/tests/*,memory:0x* - coverage html -d cover --omit=.tox/*,{{ project.package_name }}/tests/*,memory:0x* + coverage run -m pytest {posargs} --timer-top-n=10 {env:PACKAGE_NAME}/tests + coverage report --omit=.tox/*,{env:PACKAGE_NAME}/tests/*,memory:0x* + coverage html -d cover --omit=.tox/*,{env:PACKAGE_NAME}/tests/*,memory:0x* [testenv:venv] commands = {posargs} -[flake8] -show-source = true -builtins = _ -exclude = .git,.tox,dist,doc,*lib/python*,*egg,build* -ignore = E203,W503 - - [testenv:doc] deps = -r{toxinidir}/requirements.txt -r{toxinidir}/doc-requirements.txt @@ -57,3 +52,14 @@ deps = -r{toxinidir}/requirements.txt usedevelop=true allowlist_externals = echo commands = echo "Done! Usage: source .tox/develop/bin/activate" + + +[testenv:black-check] +deps = black +commands = black -l 79 {env:PACKAGE_NAME} setup.py --check + + +[testenv:black] +line-length = 79 +deps = black +commands = black -l 79 {env:PACKAGE_NAME} setup.py From 9b74024ab2e0790f6142a72047f795563a95eb4a Mon Sep 17 00:00:00 2001 From: George Melikov Date: Mon, 17 Feb 2025 12:27:16 +0300 Subject: [PATCH 2/4] Add CI template --- .../.github/workflows/publish-to-pypi.yml | 97 +++++++++++++++++++ .../py_dummy/.github/workflows/tests.yaml | 46 +++++++++ 2 files changed, 143 insertions(+) create mode 100644 templates/py_dummy/.github/workflows/publish-to-pypi.yml create mode 100644 templates/py_dummy/.github/workflows/tests.yaml diff --git a/templates/py_dummy/.github/workflows/publish-to-pypi.yml b/templates/py_dummy/.github/workflows/publish-to-pypi.yml new file mode 100644 index 0000000..c388289 --- /dev/null +++ b/templates/py_dummy/.github/workflows/publish-to-pypi.yml @@ -0,0 +1,97 @@ +name: Publish Python 🐍 distribution 📦 to PyPI + +on: + push: + tags: + - '*' + +jobs: + build: + name: Build distribution 📦 + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + - name: Install pypa/build + run: >- + python3 -m + pip install + build + --user + - name: Build a binary wheel and a source tarball + run: python3 -m build + - name: Store the distribution packages + uses: actions/upload-artifact@v4 + with: + name: python-package-distributions + path: dist/ + + publish-to-pypi: + name: >- + Publish Python 🐍 distribution 📦 to PyPI + needs: + - build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/{{ project.package_name }} + permissions: + id-token: write # IMPORTANT: mandatory for trusted publishing + + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + - name: Publish distribution 📦 to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + + github-release: + name: >- + Sign the Python 🐍 distribution 📦 with Sigstore + and upload them to GitHub Release + needs: + - publish-to-pypi + runs-on: ubuntu-latest + + permissions: + contents: write # IMPORTANT: mandatory for making GitHub Releases + id-token: write # IMPORTANT: mandatory for sigstore + + steps: + - name: Download all the dists + uses: actions/download-artifact@v4 + with: + name: python-package-distributions + path: dist/ + - name: Sign the dists with Sigstore + uses: sigstore/gh-action-sigstore-python@v3.0.0 + with: + inputs: >- + ./dist/*.tar.gz + ./dist/*.whl + - name: Create GitHub Release + env: + GITHUB_TOKEN: {% raw %}${{ github.token }}{% endraw %} + run: >- + gh release create + "$GITHUB_REF_NAME" + --repo "$GITHUB_REPOSITORY" + --notes "" + - name: Upload artifact signatures to GitHub Release + env: + GITHUB_TOKEN: {% raw %}${{ github.token }}{% endraw %} + # Upload to GitHub Release using the `gh` CLI. + # `dist/` contains the built packages, and the + # sigstore-produced signatures and certificates. + run: >- + gh release upload + "$GITHUB_REF_NAME" dist/** + --repo "$GITHUB_REPOSITORY" diff --git a/templates/py_dummy/.github/workflows/tests.yaml b/templates/py_dummy/.github/workflows/tests.yaml new file mode 100644 index 0000000..0ab9dbe --- /dev/null +++ b/templates/py_dummy/.github/workflows/tests.yaml @@ -0,0 +1,46 @@ +name: tests + +on: + push: + pull_request: + +jobs: + Lint: + runs-on: ubuntu-24.04 + strategy: + fail-fast: true + matrix: + python-version: ["3.12"] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v5 + with: + python-version: {% raw %}${{ matrix.python-version }}{% endraw %} + - name: Install tox + run: pip install tox + - name: Black + run: | + tox -e black-check + tests: + runs-on: ubuntu-24.04 + strategy: + fail-fast: true + matrix: + python-version: ["3.8", "3.10", "3.12", "3.13"] + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v5 + with: + python-version: {% raw %}${{ matrix.python-version }}{% endraw %} + - name: Install required packages + run: | + sudo apt update + sudo apt install libev-dev -y + - name: Install tox + run: pip install tox + - name: Unit tests + run: | + tox -e {% raw %}${{ matrix.python-version }}{% endraw %} + - name: Functional tests + run: | + tox -e {% raw %}${{ matrix.python-version }}{% endraw %}-functional From 9a1d9a34b4efd54c9313a264362caab966319f03 Mon Sep 17 00:00:00 2001 From: George Melikov Date: Tue, 18 Feb 2025 18:24:00 +0300 Subject: [PATCH 3/4] Add API boilerplate --- .../{{ project.package_name }}/logging.yaml | 33 +++++++ .../{{ project.package_name }}.conf | 5 ++ .../api/__init__.py | 0 .../{{ project.package_name }}/api/app.py | 68 +++++++++++++++ .../api/controllers.py | 33 +++++++ .../{{ project.package_name }}/api/routes.py | 29 +++++++ .../api/versions.py | 17 ++++ .../cmd/__init__.py | 0 .../cmd/user_api.py | 77 +++++++++++++++++ .../common/__init__.py | 0 .../common/config.py | 48 +++++++++++ .../common/constants.py | 18 ++++ .../{{ project.package_name }}/common/log.py | 85 +++++++++++++++++++ .../{{ project.package_name }}/dm/__init__.py | 0 .../{{ project.package_name }}/dm/models.py | 29 +++++++ 15 files changed, 442 insertions(+) create mode 100644 templates/py_dummy/etc/{{ project.package_name }}/logging.yaml create mode 100644 templates/py_dummy/etc/{{ project.package_name }}/{{ project.package_name }}.conf create mode 100644 templates/py_dummy/{{ project.package_name }}/api/__init__.py create mode 100644 templates/py_dummy/{{ project.package_name }}/api/app.py create mode 100644 templates/py_dummy/{{ project.package_name }}/api/controllers.py create mode 100644 templates/py_dummy/{{ project.package_name }}/api/routes.py create mode 100644 templates/py_dummy/{{ project.package_name }}/api/versions.py create mode 100644 templates/py_dummy/{{ project.package_name }}/cmd/__init__.py create mode 100644 templates/py_dummy/{{ project.package_name }}/cmd/user_api.py create mode 100644 templates/py_dummy/{{ project.package_name }}/common/__init__.py create mode 100644 templates/py_dummy/{{ project.package_name }}/common/config.py create mode 100644 templates/py_dummy/{{ project.package_name }}/common/constants.py create mode 100644 templates/py_dummy/{{ project.package_name }}/common/log.py create mode 100644 templates/py_dummy/{{ project.package_name }}/dm/__init__.py create mode 100644 templates/py_dummy/{{ project.package_name }}/dm/models.py diff --git a/templates/py_dummy/etc/{{ project.package_name }}/logging.yaml b/templates/py_dummy/etc/{{ project.package_name }}/logging.yaml new file mode 100644 index 0000000..f7600ac --- /dev/null +++ b/templates/py_dummy/etc/{{ project.package_name }}/logging.yaml @@ -0,0 +1,33 @@ +version: 1 +formatters: + aardvark: + format: '%(asctime)15s.%(msecs)03d %(processName)s pid:%(process)d tid:%(thread)d %(levelname)s %(name)s:%(lineno)d %(message)s' + datefmt: '%Y-%m-%dT%H:%M:%S' +# this one should only be used by handlers that support topology_id attribute +# and since it may be used by multiple modules, actual_module attribute +# should also be added (module will give a short name, pathname is too long) + +handlers: + console: + class : logging.StreamHandler + formatter: aardvark + stream : ext://sys.stdout + +loggers: +# by default all existing loggers are disabled upon the application +# of this config. To re-enable a logger and it's childer just add it +# to the loggers section with any even empty fields. + camel: + handlers: [console] + level: WARNING + propagate: False + + {{ project.package_name }}: {} + bjoern: {} + gcl_looper: {} + restalchemy: {} + sentry_sdk: {} + +root: + handlers: [console] + level: DEBUG diff --git a/templates/py_dummy/etc/{{ project.package_name }}/{{ project.package_name }}.conf b/templates/py_dummy/etc/{{ project.package_name }}/{{ project.package_name }}.conf new file mode 100644 index 0000000..685450f --- /dev/null +++ b/templates/py_dummy/etc/{{ project.package_name }}/{{ project.package_name }}.conf @@ -0,0 +1,5 @@ +[db] +connection_url = postgresql://{{ project.package_name }}:pass@172.17.0.2:5432/{{ project.package_name }} + +[logging] +config = logging.yaml diff --git a/templates/py_dummy/{{ project.package_name }}/api/__init__.py b/templates/py_dummy/{{ project.package_name }}/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/templates/py_dummy/{{ project.package_name }}/api/app.py b/templates/py_dummy/{{ project.package_name }}/api/app.py new file mode 100644 index 0000000..0b1922b --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/api/app.py @@ -0,0 +1,68 @@ +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from restalchemy.api import applications +from restalchemy.api.middlewares import contexts +from restalchemy.api.middlewares import logging +from restalchemy.api.middlewares import errors +from restalchemy.api.middlewares import retry_on_error +from restalchemy.api import routes +from restalchemy.storage import exceptions as storage_exc + +from {{ project.package_name }}.api import controllers +from {{ project.package_name }}.api import routes as app_routes +from {{ project.package_name }}.api import versions + + +class UserApiApp(routes.Route): + __controller__ = controllers.RootController + __allow_methods__ = [routes.FILTER] + + +# Route to /1.0.0/ endpoint. +setattr(UserApiApp, versions.API_VERSION_1_0, routes.route(app_routes.ApiEndpointRoute)) + + +def get_user_api_application(): + return UserApiApp + + +def attach_middlewares(app, middlewares_list): + for middleware in middlewares_list: + app = middleware(application=app) + return app + + +def configure_middleware(middleware_class, *args, **kwargs): + def build_middleware(application): + return middleware_class(application=application, *args, **kwargs) + + return build_middleware + + +def build_wsgi_application(): + return attach_middlewares( + applications.Application(get_user_api_application()), + ( + contexts.ContextMiddleware, + configure_middleware( + middleware_class=retry_on_error.RetryOnErrorsMiddleware, + exceptions=storage_exc.DeadLock, + ), + errors.ErrorsHandlerMiddleware, + logging.LoggingMiddleware, + ), + ) diff --git a/templates/py_dummy/{{ project.package_name }}/api/controllers.py b/templates/py_dummy/{{ project.package_name }}/api/controllers.py new file mode 100644 index 0000000..94fe0c8 --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/api/controllers.py @@ -0,0 +1,33 @@ +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from restalchemy.api import controllers as ra_controllers + +from {{ project.package_name }}.api import versions + + +class RootController(ra_controllers.Controller): + """Controller for / endpoint""" + + def filter(self, filters): + return (versions.API_VERSION_1_0,) + + +class ApiEndpointController(ra_controllers.Controller): + """Controller for /v1.0/ endpoint""" + + def filter(self, filters): + return [] diff --git a/templates/py_dummy/{{ project.package_name }}/api/routes.py b/templates/py_dummy/{{ project.package_name }}/api/routes.py new file mode 100644 index 0000000..16a7fb4 --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/api/routes.py @@ -0,0 +1,29 @@ +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from restalchemy.api import routes + +from {{ project.package_name }}.api import controllers + + +class ApiEndpointRoute(routes.Route): + """Handler for /v1.0/ endpoint""" + + __controller__ = controllers.ApiEndpointController + __allow_methods__ = [routes.FILTER] + + # route to /v1.0/examples/[] + # examples = routes.route(ExampleRoute) diff --git a/templates/py_dummy/{{ project.package_name }}/api/versions.py b/templates/py_dummy/{{ project.package_name }}/api/versions.py new file mode 100644 index 0000000..a137e81 --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/api/versions.py @@ -0,0 +1,17 @@ +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +API_VERSION_1_0 = "v1.0" diff --git a/templates/py_dummy/{{ project.package_name }}/cmd/__init__.py b/templates/py_dummy/{{ project.package_name }}/cmd/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/templates/py_dummy/{{ project.package_name }}/cmd/user_api.py b/templates/py_dummy/{{ project.package_name }}/cmd/user_api.py new file mode 100644 index 0000000..4a05832 --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/cmd/user_api.py @@ -0,0 +1,77 @@ +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging +import sys + +from gcl_looper.services import bjoern_service +from oslo_config import cfg +from restalchemy.storage.sql import engines + +from {{ project.package_name }}.api import app +from {{ project.package_name }}.common import config +from {{ project.package_name }}.common import log as infra_log + + +api_cli_opts = [ + cfg.StrOpt("bind-host", default="127.0.0.1", help="The host IP to bind to"), + cfg.IntOpt("bind-port", default=8080, help="The port to bind to"), + cfg.IntOpt("workers", default=1, help="How many http servers should be started"), +] + +db_opts = [ + cfg.StrOpt( + "connection-url", + default="postgresql://{{ project.package_name }}:pass" + "@127.0.0.1:5432/{{ project.package_name }}", + help="Connection URL to db", + ), +] + + +DOMAIN = "user_api" + +CONF = cfg.CONF +CONF.register_cli_opts(api_cli_opts, DOMAIN) +CONF.register_opts(db_opts, "db") + + +def main(): + # Parse config + config.parse(sys.argv[1:]) + + # Configure logging + infra_log.configure() + log = logging.getLogger(__name__) + + engines.engine_factory.configure_factory(db_url=CONF.db.connection_url) + + log.info("Start service on %s:%s", CONF[DOMAIN].bind_host, CONF[DOMAIN].bind_port) + + service = bjoern_service.BjoernService( + wsgi_app=app.build_wsgi_application(), + host=CONF[DOMAIN].bind_host, + port=CONF[DOMAIN].bind_port, + bjoern_kwargs=dict(reuse_port=True), + ) + + service.start() + + log.info("Bye!!!") + + +if __name__ == "__main__": + main() diff --git a/templates/py_dummy/{{ project.package_name }}/common/__init__.py b/templates/py_dummy/{{ project.package_name }}/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/templates/py_dummy/{{ project.package_name }}/common/config.py b/templates/py_dummy/{{ project.package_name }}/common/config.py new file mode 100644 index 0000000..5591921 --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/common/config.py @@ -0,0 +1,48 @@ +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging + +from oslo_config import cfg + +from {{ project.package_name }}.common import constants +from {{ project.package_name }} import version + + +GLOBAL_SERVICE_NAME = constants.GLOBAL_SERVICE_NAME + + +_CONFIG_NOT_FOUND_MESSAGE = ( + "Unable to find configuration file in the" + " default search paths (~/.%(service_name)s/, ~/," + " /etc/%(service_name)s/, /etc/) and the '--config-file' option!" + % {"service_name": GLOBAL_SERVICE_NAME} +) + + +def parse(args): + cfg.CONF( + args=args, + project=GLOBAL_SERVICE_NAME, + version="%s %s" + % ( + GLOBAL_SERVICE_NAME.capitalize(), + version.version_info, + ), + ) + if not cfg.CONF.config_file: + logging.warning(_CONFIG_NOT_FOUND_MESSAGE) + return cfg.CONF.config_file diff --git a/templates/py_dummy/{{ project.package_name }}/common/constants.py b/templates/py_dummy/{{ project.package_name }}/common/constants.py new file mode 100644 index 0000000..b6742fd --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/common/constants.py @@ -0,0 +1,18 @@ +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# project +GLOBAL_SERVICE_NAME = "{{ project.package_name }}" diff --git a/templates/py_dummy/{{ project.package_name }}/common/log.py b/templates/py_dummy/{{ project.package_name }}/common/log.py new file mode 100644 index 0000000..593d136 --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/common/log.py @@ -0,0 +1,85 @@ +import logging +from logging import config as logging_config +import sys + +from oslo_config import cfg +import yaml + + +DEFAULT_CONFIG = { + "version": 1, + "formatters": { + "aardvark": { + "datefmt": "%Y-%m-%d,%H:%M:%S", + "format": "%(asctime)15s.%(msecs)03d %(processName)s" + " pid:%(process)d tid:%(thread)d %(levelname)s" + " %(name)s:%(lineno)d %(message)s", + } + }, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "formatter": "aardvark", + "stream": "ext://sys.stderr", + }, + }, + "loggers": { + "node-manager": {}, + }, + "root": {"level": "DEBUG", "handlers": ["console"]}, +} + + +logging_opts = [ + cfg.StrOpt( + "config", + default="logging.yaml", + help="Logging subsystem configuration YAML file", + ) +] + + +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +cfg.CONF.register_cli_opts(logging_opts, "logging") + + +class ConfigNotFound(Exception): + pass + + +def configure(): + config = cfg.CONF.logging.config + config_file = cfg.CONF.find_file(config) + + if config_file is None: + config_data = DEFAULT_CONFIG + else: + with open(config_file) as f: + config_data = yaml.safe_load(f) + + logging_config.dictConfig(config_data) + + if config_data == DEFAULT_CONFIG: + logging.getLogger(__name__).warning( + "Logging configuration %s not found - using defaults", config + ) + + +def die(logger, message): + logger.error(message) + sys.exit(1) diff --git a/templates/py_dummy/{{ project.package_name }}/dm/__init__.py b/templates/py_dummy/{{ project.package_name }}/dm/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/templates/py_dummy/{{ project.package_name }}/dm/models.py b/templates/py_dummy/{{ project.package_name }}/dm/models.py new file mode 100644 index 0000000..c4b1f7f --- /dev/null +++ b/templates/py_dummy/{{ project.package_name }}/dm/models.py @@ -0,0 +1,29 @@ +# Copyright {{ functions.now().strftime('%Y') }} {{ author.name }}. +# +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from datetime import datetime, timezone + +from restalchemy.dm import filters +from restalchemy.dm import models +from restalchemy.dm import properties +from restalchemy.dm import relationships +from restalchemy.dm import types +from restalchemy.storage.sql import orm + + +# class ExampleModel(models.ModelWithUUID, orm.SQLStorableMixin): +# __tablename__ = "table_name" +# name = properties.property(types.String(max_length=255), default="") From 554488e3db9ce1445a4e8c5d84d26965862708c2 Mon Sep 17 00:00:00 2001 From: George Melikov Date: Tue, 18 Feb 2025 18:35:13 +0300 Subject: [PATCH 4/4] pep8: ignore templates, .py files may be invalid at this stage --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index cf50c32..15c9bc8 100644 --- a/tox.ini +++ b/tox.ini @@ -38,7 +38,7 @@ commands = {posargs} [flake8] show-source = true builtins = _ -exclude = .git,.tox,dist,doc,*lib/python*,*egg,build* +exclude = .git,.tox,dist,doc,*lib/python*,*egg,build*,templates/* ignore = E203,W503