diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 0000000..a71ba82 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,28 @@ +name-template: 'v$NEXT_PATCH_VERSION 🧮' +tag-template: '$NEXT_PATCH_VERSION' +categories: + - title: 'New Features' + label: 'enhancement' + - title: 'Deprecation' + label: 'deprecation' + - title: 'Bug Fixes' + labels: + - 'bug' + - 'Fix' + - title: 'Documentation' + label: 'documentation' + - title: 'Maintenance' + labels: + - 'maintenance' + - 'dependencies' + - 'github_actions' + - title: 'Testing' + label: 'tests' + - title: 'Under the Bonnet' + label: 'code improvement' + - title: 'Continuous Integration' + label: 'CI' +template: | + # What's Changed + + $CHANGES diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml new file mode 100644 index 0000000..66ef8e0 --- /dev/null +++ b/.github/workflows/build-test.yml @@ -0,0 +1,50 @@ +name: Build and test + +on: + workflow_dispatch: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + check-black: + # fail it if doesn't conform to black + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: psf/black@stable + with: + options: "--check --verbose" + + build-and-test: + + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + python-version: ["3.9", "3.10"] + + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + cache: 'pip' + cache-dependency-path: 'requirements_tests.txt' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements_tests.txt + pip install -e . + - name: Lint with flake8 + # fail it if doesn't pass flake8 + run: | + flake8 . --statistics + - name: Test with pytest + # fail it if doesn't pass test suite + run: | + pytest \ No newline at end of file diff --git a/.github/workflows/draft-release-notes.yml b/.github/workflows/draft-release-notes.yml new file mode 100644 index 0000000..739280f --- /dev/null +++ b/.github/workflows/draft-release-notes.yml @@ -0,0 +1,16 @@ +name: Release Drafter + +on: + push: + branches: + - main + +# Updates next release notes on any push to main. Label a PR to categorize it +# in accordance with .github/release_drafter.yml. +jobs: + update_release_draft: + runs-on: ubuntu-latest + steps: + - uses: release-drafter/release-drafter@v5 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..603ba09 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,63 @@ +# Workflow to upload a Python Package using Twine when a release is created +name: Release to PyPI + +on: + release: + types: [released] + +permissions: + contents: read + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Set up Python + uses: actions/setup-python@v4 + with: + python-version: '3.x' + + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + pip install build + + - name: Build package + run: python -m build + + - name: Publish to Test PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_TEST_API_TOKEN }} + repository_url: https://test.pypi.org/legacy/ + + - name: Install from testpypi and import + run: | + i=0 + while (($i<12)) && [ "${{ github.ref_name }}" != $(pip index versions -i https://test.pypi.org/simple --pre beanahead | cut -d'(' -f2 | cut -d')' -f1 | sed 1q) ];\ + do echo waiting for package to appear in test index, sleeping 5s; sleep 5s; let i++; done + pip install --index-url https://test.pypi.org/simple beanahead==${{ github.ref_name }} --no-deps + pip install -r requirements.txt + python -c 'import beanahead;print(beanahead.__version__)' + + - name: Clean pip + run: | + pip uninstall -y beanahead + pip cache purge + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 + with: + user: __token__ + password: ${{ secrets.PYPI_API_TOKEN }} + + - name: Install and import + run: | + i=0 + while (($i<12)) && [ "${{ github.ref_name }}" != $(pip index versions -i https://pypi.org/simple --pre beanahead | cut -d'(' -f2 | cut -d')' -f1 | sed 1q) ];\ + do echo waiting for package to appear in index, sleeping 5s; sleep 5s; let i++; done + pip install --index-url https://pypi.org/simple beanahead==${{ github.ref_name }} + python -c 'import beanahead;print(beanahead.__version__)' diff --git a/pyproject.toml b/pyproject.toml index d638c85..966cc73 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,15 +39,18 @@ dependencies = [ dynamic = ["version"] [project.optional-dependencies] -dev = [ +tests = [ "black", "flake8", "flake8-docstrings", + "pytest", +] +dev = [ + "beanahead[tests]", "mypy", "pip-tools", "pre-commit", "pylint", - "pytest", ] [project.urls] diff --git a/requirements.txt b/requirements.txt index 9af342f..194b8c5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -20,22 +20,24 @@ chardet==5.0.0 # via beancount charset-normalizer==2.1.1 # via requests -colorama==0.4.5 +colorama==0.4.6 # via pytest -google-api-core==2.10.1 +exceptiongroup==1.0.4 + # via pytest +google-api-core==2.10.2 # via google-api-python-client -google-api-python-client==2.64.0 +google-api-python-client==2.66.0 # via beancount -google-auth==2.12.0 +google-auth==2.14.1 # via # google-api-core # google-api-python-client # google-auth-httplib2 google-auth-httplib2==0.1.0 # via google-api-python-client -googleapis-common-protos==1.56.4 +googleapis-common-protos==1.57.0 # via google-api-core -httplib2==0.20.4 +httplib2==0.21.0 # via # google-api-python-client # google-auth-httplib2 @@ -45,22 +47,20 @@ iniconfig==1.1.1 # via pytest lxml==4.9.1 # via beancount -numpy==1.23.3 +numpy==1.23.4 # via pandas packaging==21.3 # via pytest -pandas==1.5.0 +pandas==1.5.1 # via beanahead (pyproject.toml) pluggy==1.0.0 # via pytest ply==3.11 # via beancount -protobuf==4.21.7 +protobuf==4.21.9 # via # google-api-core # googleapis-common-protos -py==1.11.0 - # via pytest pyasn1==0.4.8 # via # pyasn1-modules @@ -71,13 +71,13 @@ pyparsing==3.0.9 # via # httplib2 # packaging -pytest==7.1.3 +pytest==7.2.0 # via beancount python-dateutil==2.8.2 # via # beancount # pandas -pytz==2022.4 +pytz==2022.6 # via pandas requests==2.28.1 # via diff --git a/extra_requirements/requirements_dev.txt b/requirements_dev.txt similarity index 84% rename from extra_requirements/requirements_dev.txt rename to requirements_dev.txt index 4a84890..4535e9e 100644 --- a/extra_requirements/requirements_dev.txt +++ b/requirements_dev.txt @@ -2,9 +2,9 @@ # This file is autogenerated by pip-compile with python 3.9 # To update, run: # -# pip-compile --extra=dev --output-file=./extra_requirements/requirements_dev.txt pyproject.toml +# pip-compile --extra=dev --output-file=requirements_dev.txt pyproject.toml # -astroid==2.12.10 +astroid==2.12.12 # via pylint attrs==22.1.0 # via pytest @@ -12,11 +12,11 @@ beancount==2.3.5 # via beanahead (pyproject.toml) beautifulsoup4==4.11.1 # via beancount -black==22.8.0 +black==22.10.0 # via beanahead (pyproject.toml) bottle==0.12.23 # via beancount -build==0.8.0 +build==0.9.0 # via pip-tools cachetools==5.2.0 # via google-auth @@ -32,16 +32,18 @@ click==8.1.3 # via # black # pip-tools -colorama==0.4.5 +colorama==0.4.6 # via # build # click # pylint # pytest -dill==0.3.5.1 +dill==0.3.6 # via pylint distlib==0.3.6 # via virtualenv +exceptiongroup==1.0.4 + # via pytest filelock==3.8.0 # via virtualenv flake8==5.0.4 @@ -50,24 +52,24 @@ flake8==5.0.4 # flake8-docstrings flake8-docstrings==1.6.0 # via beanahead (pyproject.toml) -google-api-core==2.10.1 +google-api-core==2.10.2 # via google-api-python-client -google-api-python-client==2.64.0 +google-api-python-client==2.66.0 # via beancount -google-auth==2.12.0 +google-auth==2.14.1 # via # google-api-core # google-api-python-client # google-auth-httplib2 google-auth-httplib2==0.1.0 # via google-api-python-client -googleapis-common-protos==1.56.4 +googleapis-common-protos==1.57.0 # via google-api-core -httplib2==0.20.4 +httplib2==0.21.0 # via # google-api-python-client # google-auth-httplib2 -identify==2.5.6 +identify==2.5.8 # via pre-commit idna==3.4 # via requests @@ -75,7 +77,7 @@ iniconfig==1.1.1 # via pytest isort==5.10.1 # via pylint -lazy-object-proxy==1.7.1 +lazy-object-proxy==1.8.0 # via astroid lxml==4.9.1 # via beancount @@ -83,7 +85,7 @@ mccabe==0.7.0 # via # flake8 # pylint -mypy==0.982 +mypy==0.991 # via beanahead (pyproject.toml) mypy-extensions==0.4.3 # via @@ -91,21 +93,21 @@ mypy-extensions==0.4.3 # mypy nodeenv==1.7.0 # via pre-commit -numpy==1.23.3 +numpy==1.23.4 # via pandas packaging==21.3 # via # build # pytest -pandas==1.5.0 +pandas==1.5.1 # via beanahead (pyproject.toml) -pathspec==0.10.1 +pathspec==0.10.2 # via black pep517==0.13.0 # via build -pip-tools==6.9.0 +pip-tools==6.10.0 # via beanahead (pyproject.toml) -platformdirs==2.5.2 +platformdirs==2.5.4 # via # black # pylint @@ -116,12 +118,10 @@ ply==3.11 # via beancount pre-commit==2.20.0 # via beanahead (pyproject.toml) -protobuf==4.21.7 +protobuf==4.21.9 # via # google-api-core # googleapis-common-protos -py==1.11.0 - # via pytest pyasn1==0.4.8 # via # pyasn1-modules @@ -134,13 +134,13 @@ pydocstyle==6.1.1 # via flake8-docstrings pyflakes==2.5.0 # via flake8 -pylint==2.15.3 +pylint==2.15.5 # via beanahead (pyproject.toml) pyparsing==3.0.9 # via # httplib2 # packaging -pytest==7.1.3 +pytest==7.2.0 # via # beanahead (pyproject.toml) # beancount @@ -148,7 +148,7 @@ python-dateutil==2.8.2 # via # beancount # pandas -pytz==2022.4 +pytz==2022.6 # via pandas pyyaml==6.0 # via pre-commit @@ -177,9 +177,9 @@ tomli==2.0.1 # pep517 # pylint # pytest -tomlkit==0.11.5 +tomlkit==0.11.6 # via pylint -typing-extensions==4.3.0 +typing-extensions==4.4.0 # via # astroid # black @@ -189,9 +189,9 @@ uritemplate==4.1.1 # via google-api-python-client urllib3==1.26.12 # via requests -virtualenv==20.16.5 +virtualenv==20.16.7 # via pre-commit -wheel==0.37.1 +wheel==0.38.4 # via pip-tools wrapt==1.14.1 # via astroid diff --git a/requirements_tests.txt b/requirements_tests.txt new file mode 100644 index 0000000..0135237 --- /dev/null +++ b/requirements_tests.txt @@ -0,0 +1,134 @@ +# +# This file is autogenerated by pip-compile with python 3.9 +# To update, run: +# +# pip-compile --extra=tests --output-file=requirements_tests.txt pyproject.toml +# +attrs==22.1.0 + # via pytest +beancount==2.3.5 + # via beanahead (pyproject.toml) +beautifulsoup4==4.11.1 + # via beancount +black==22.10.0 + # via beanahead (pyproject.toml) +bottle==0.12.23 + # via beancount +cachetools==5.2.0 + # via google-auth +certifi==2022.9.24 + # via requests +chardet==5.0.0 + # via beancount +charset-normalizer==2.1.1 + # via requests +click==8.1.3 + # via black +colorama==0.4.6 + # via + # click + # pytest +exceptiongroup==1.0.4 + # via pytest +flake8==5.0.4 + # via + # beanahead (pyproject.toml) + # flake8-docstrings +flake8-docstrings==1.6.0 + # via beanahead (pyproject.toml) +google-api-core==2.10.2 + # via google-api-python-client +google-api-python-client==2.66.0 + # via beancount +google-auth==2.14.1 + # via + # google-api-core + # google-api-python-client + # google-auth-httplib2 +google-auth-httplib2==0.1.0 + # via google-api-python-client +googleapis-common-protos==1.57.0 + # via google-api-core +httplib2==0.21.0 + # via + # google-api-python-client + # google-auth-httplib2 +idna==3.4 + # via requests +iniconfig==1.1.1 + # via pytest +lxml==4.9.1 + # via beancount +mccabe==0.7.0 + # via flake8 +mypy-extensions==0.4.3 + # via black +numpy==1.23.4 + # via pandas +packaging==21.3 + # via pytest +pandas==1.5.1 + # via beanahead (pyproject.toml) +pathspec==0.10.2 + # via black +platformdirs==2.5.4 + # via black +pluggy==1.0.0 + # via pytest +ply==3.11 + # via beancount +protobuf==4.21.9 + # via + # google-api-core + # googleapis-common-protos +pyasn1==0.4.8 + # via + # pyasn1-modules + # rsa +pyasn1-modules==0.2.8 + # via google-auth +pycodestyle==2.9.1 + # via flake8 +pydocstyle==6.1.1 + # via flake8-docstrings +pyflakes==2.5.0 + # via flake8 +pyparsing==3.0.9 + # via + # httplib2 + # packaging +pytest==7.2.0 + # via + # beanahead (pyproject.toml) + # beancount +python-dateutil==2.8.2 + # via + # beancount + # pandas +pytz==2022.6 + # via pandas +requests==2.28.1 + # via + # beancount + # google-api-core +rsa==4.9 + # via google-auth +six==1.16.0 + # via + # google-auth + # google-auth-httplib2 + # python-dateutil +snowballstemmer==2.2.0 + # via pydocstyle +soupsieve==2.3.2.post1 + # via beautifulsoup4 +tomli==2.0.1 + # via + # black + # pytest +typing-extensions==4.4.0 + # via black +uritemplate==4.1.1 + # via google-api-python-client +urllib3==1.26.12 + # via requests diff --git a/tests/conftest.py b/tests/conftest.py index 1298cd1..d83b323 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -31,9 +31,13 @@ # invalid-name: names in tests not expected to strictly conform with snake_case. +ENCODING = "utf-8" TEST_ROOT = Path(__file__).parent TEMP_DIR = TEST_ROOT / r"./_temp" -ENCODING = "utf-8" +TEMP_SUBDIR = TEMP_DIR / r"./_tempsub" +for temp_dir in (TEMP_DIR, TEMP_SUBDIR): + if not temp_dir.is_dir(): + temp_dir.mkdir() def set_cl_args(cl: str): @@ -98,7 +102,6 @@ def cwd_as_temp_dir(temp_dir) -> abc.Iterator[Path]: def _clean_test_dir(): """Remove all files and directories from the test directory""" - assert TEMP_DIR.is_dir() for dirpath, dirname, filenames in os.walk(TEMP_DIR): for filename in filenames: path = Path(dirpath) / filename diff --git a/tests/test_errors.py b/tests/test_errors.py index e2ea7b8..c274c7c 100644 --- a/tests/test_errors.py +++ b/tests/test_errors.py @@ -68,8 +68,7 @@ def test_BeanaheadWriteError(path): expected = ( f"An error occurred when attempting to overwrite '{path}'." " The following files have been reverted to their most recent saved content:" - "\nreverted\\path\\x.beancount" - "\nreverted\\path\\rx.beancount" + f"\n{str(reverted[0])}\n{str(reverted[1])}" ) assert str(error) == expected diff --git a/tests/test_utils.py b/tests/test_utils.py index fbc215d..91885d5 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -305,7 +305,7 @@ def assertions(expected_path: Path, file_key: str): # verify can pass dirpath key = "x" - rel_path = "./_temp2" + rel_path = "./_tempsub" expected_path = cwd_as_temp_dir / rel_path / f"{key}.beancount" assert not expected_path.is_file() f(key, dirpath=rel_path) @@ -360,7 +360,7 @@ def assertions(expected_path: Path, file_key: str): # verify can pass dirpath key = "x" - rel_path = "./_temp2" + rel_path = "./_tempsub" expected_path = cwd_as_temp_dir / rel_path / f"{key}.beancount" assert not expected_path.is_file() set_cl_args(f"make {key} --dirpath {rel_path}")