diff --git a/.flake8 b/.flake8 index e41dc44..cdabf5d 100644 --- a/.flake8 +++ b/.flake8 @@ -1,5 +1,5 @@ [flake8] -ignore = RST303,RST304,W503 +ignore = W503 omit = dist per-file-ignores = diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..65e566a --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,87 @@ +name: Build + +on: + push: + branches: [ master ] + tags: [ 'v*' ] + + pull_request: + branches: [ master ] + +jobs: + test: + name: Pytest + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ['3.10', '3.11', '3.12'] + env: + PREFIX: /usr + FLAKE8: flake8 + PYTEST: pytest + COVERAGE: coverage + services: + postgres: + image: postgres + env: + POSTGRES_PASSWORD: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + git clone https://github.com/pylover/python-makelib.git make + make env ENV=ci + sudo cp `which bddcli-bootstrapper` /usr/local/bin + - name: Lint + run: make lint + - name: Test + run: make cover + - name: Coveralls + run: coveralls + env: + COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }} + + coveralls-finish: + name: Coveralls finish + needs: test + runs-on: ubuntu-latest + steps: + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + - name: Install dependencies + run: python -m pip install coveralls + - name: Coveralls Finished + run: coveralls --finish + env: + GITHUB_TOKEN: ${{ secrets.PAT }} + + release: + name: Github Release + needs: test + runs-on: ubuntu-latest + if: github.event_name == 'push' && contains(github.ref, 'refs/tags/') + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.PAT }} + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + draft: false + prerelease: false diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..62e3512 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,28 @@ +name: Deploy + +on: + release: + types: [created] + +jobs: + deploypypi: + name: Deploy to PyPI + runs-on: ubuntu-latest + env: + PREFIX: /usr + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v5 + - name: Install dependencies + run: | + git clone https://github.com/pylover/python-makelib.git make + make env ENV=ci + - name: Create distributions + run: make dist + - name: Publish a Python distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1.9 + with: + user: __token__ + password: ${{ secrets.PYPI_TOKEN }} diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..426e7b5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "make"] + path = make + url = git@github.com:pylover/python-makelib.git diff --git a/Makefile b/Makefile index 908988b..837ace1 100644 --- a/Makefile +++ b/Makefile @@ -1,58 +1,6 @@ -PY = python3 -PIP = pip3 -TEST_DIR = tests -PRJ = yhttp.ext.sqlalchemy -PYTEST_FLAGS = -v -HERE = $(shell readlink -f `dirname .`) -VENVNAME = $(shell basename $(HERE) | cut -d'-' -f1) -VENV = $(HOME)/.virtualenvs/$(VENVNAME) - - -.PHONY: test -test: - pytest $(PYTEST_FLAGS) $(TEST_DIR) - - -.PHONY: cover -cover: - pytest $(PYTEST_FLAGS) --cov=$(PRJ) $(TEST_DIR) - - -.PHONY: lint -lint: - flake8 - - -.PHONY: venv -venv: - python3 -m venv $(VENV) - - -.PHONY: env -env: - $(PIP) install -r requirements-dev.txt - $(PIP) install -e . - - -.PHONY: sdist -sdist: - $(PY) setup.py sdist - - -.PHONY: bdist -bdist: - $(PY) setup.py bdist_egg - - -.PHONY: dist -dist: sdist bdist - - -.PHONY: pypi -pypi: dist - twine upload dist/*.gz dist/*.egg - - -.PHONY: clean -clean: - rm -rf build/* +PKG = yhttp.ext.sqlalchemy +PKG_NAME = yhttp-sqlalchemy +include make/common.mk +include make/test.mk +include make/sphinx.mk +include make/pypi.mk diff --git a/activate.sh b/activate.sh deleted file mode 100755 index d14b517..0000000 --- a/activate.sh +++ /dev/null @@ -1,15 +0,0 @@ -# Pick first word of directory as venv name -HERE=`dirname "$(readlink -f "$BASH_SOURCE")"` -VENVSROOT=${HOME}/.virtualenvs - -# If the first argument was not provided, use current directory name. -if [ -z "${1:-}" ]; then - DIRNAME=$(basename ${HERE}) - VENVNAME=$(echo ${DIRNAME} | cut -d'-' -f1) - VENV=${VENVSROOT}/${VENVNAME} -else - VENV=${VENVSROOT}/${1:-} -fi - - -source ${VENV}/bin/activate diff --git a/make b/make new file mode 160000 index 0000000..d3f71f9 --- /dev/null +++ b/make @@ -0,0 +1 @@ +Subproject commit d3f71f91c4157ebc1b31a9a413326e35e2435b38 diff --git a/requirements-ci.txt b/requirements-ci.txt index 4b5e3f4..23f05ee 100644 --- a/requirements-ci.txt +++ b/requirements-ci.txt @@ -1,8 +1,8 @@ -bddrest >= 3.0.2, < 4 +bddrest >= 4, < 5 bddcli >= 2.5.1, < 3 coverage < 6 coveralls pytest >= 4.4.0 pytest-cov flake8 -git+https://github.com/yhttp/yhttp-devutils.git#v1.1.0 +yhttp-dev >= 3.1.1 diff --git a/setup.py b/setup.py index b86a99c..4a7ccb5 100644 --- a/setup.py +++ b/setup.py @@ -1,7 +1,9 @@ -from setuptools import setup import os.path import re +from setuptools import setup, find_namespace_packages + + # reading package's version (same way sqlalchemy does) with open( os.path.join( @@ -16,9 +18,9 @@ dependencies = [ - 'yhttp >= 3.9.0, < 4', + 'yhttp >= 5, < 6', + 'yhttp-dbmanager >= 4, < 5', 'sqlalchemy >= 2', - 'psycopg2', ] @@ -31,9 +33,13 @@ description='SQLAlchemy extension for yhttp.', long_description=open('README.md').read(), long_description_content_type='text/markdown', # This is important! - install_requires=dependencies, - packages=['yhttp.ext.sqlalchemy'], license='MIT', + install_requires=dependencies, + packages=find_namespace_packages( + where='.', + include=['yhttp.ext.sqlalchemy'], + exclude=['tests'], + ), classifiers=[ 'Environment :: Console', 'Environment :: Web Environment', diff --git a/tests/conftest.py b/tests/conftest.py index 8a99283..a2e1ac8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,8 +3,8 @@ import bddrest import pytest -from yhttp import Application -from yhttp.ext.sqlalchemy.fixtures import freshdb +from yhttp.core import Application +from yhttp.dev.fixtures import freshdb, cicd @pytest.fixture diff --git a/tests/test_cli.py b/tests/test_cli.py index ee54b2e..8b430b3 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,10 +1,14 @@ +import os + from bddcli import Given, Application as CLIApplication, status, stderr, \ when, stdout import easycli -from yhttp import Application from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from sqlalchemy import String -from yhttp.ext.sqlalchemy import install +from yhttp.core import Application +from yhttp.dev.fixtures import CICD + +from yhttp.ext import dbmanager, sqlalchemy as saext class Bar(easycli.SubCommand): @@ -14,11 +18,11 @@ def __call__(self, args): print('bar') -app = Application() -app.settings.merge(''' -db: - url: postgresql://:@/foo -''') +class Baz(easycli.SubCommand): + __command__ = 'baz' + + def __call__(self, args): + print('baz') class Base(DeclarativeBase): @@ -32,13 +36,30 @@ class Foo(Base): title: Mapped[str] = mapped_column(String(30)) -install(app, Base, cliarguments=[Bar], create_objects=True) +_host = os.environ.get('YHTTP_DB_DEFAULT_HOST', 'localhost' if CICD else '') +_user = os.environ.get('YHTTP_DB_DEFAULT_USER', 'postgres' if CICD else '') +_pass = os.environ.get('YHTTP_DB_DEFAULT_PASS', 'postgres' if CICD else '') + + +app = Application() +app.settings.merge(f''' +db: + url: postgresql://{_user}:{_pass}@{_host}/foo +''') +dbmanager.install(app, cliarguments=[Bar]) +saext.install(app, Base, cliarguments=[Baz], create_objects=True) app.ready() -def test_applicationcli(): +def test_applicationcli(cicd): cliapp = CLIApplication('example', 'tests.test_cli:app.climain') - with Given(cliapp, 'db'): + env = os.environ.copy() + if cicd: + env.setdefault('YHTTP_DB_DEFAULT_HOST', 'localhost') + env.setdefault('YHTTP_DB_DEFAULT_ADMINUSER', 'postgres') + env.setdefault('YHTTP_DB_DEFAULT_ADMINPASS', 'postgres') + + with Given(cliapp, 'db', environ=env): assert stderr == '' assert status == 0 diff --git a/tests/test_extension.py b/tests/test_extension.py index b51a3f1..bc78e84 100644 --- a/tests/test_extension.py +++ b/tests/test_extension.py @@ -1,9 +1,10 @@ import pytest from bddrest import status, response, when -from yhttp import json, statuses from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column from sqlalchemy import select, String +from yhttp.core import json, statuses + from yhttp.ext.sqlalchemy import install @@ -83,7 +84,7 @@ def test_exceptions(app, freshdb): class Base(DeclarativeBase): pass - dbsession = install(app, Base) # noqa: F841 + install(app, Base) if 'db' in app.settings: del app.settings['db']