Skip to content

Commit

Permalink
Use invoke to standardize checks and tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
icgood committed Mar 19, 2022
1 parent ca3b5f7 commit 10d7e6b
Show file tree
Hide file tree
Showing 27 changed files with 299 additions and 91 deletions.
6 changes: 0 additions & 6 deletions .github/release-drafter.yml

This file was deleted.

22 changes: 8 additions & 14 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,15 @@ jobs:
uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel coveralls
python -m pip install --upgrade -r requirements-dev.txt
- name: Lint with flake8
- name: Install build tools
run: |
flake8 pymapadmin test
- name: Type checking with mypy
python -m pip install --upgrade pip setuptools wheel invoke coveralls
- name: Install package and dependencies
run: |
mypy pymapadmin test
- name: Test with pytest
invoke install
- name: Run test suites, type checks, and linters
run: |
py.test --cov=pymapadmin
invoke validate
- name: Report test coverage to Coveralls
if: success()
env:
Expand All @@ -53,9 +49,7 @@ jobs:
python-version: '3.10'
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade -r requirements-dev.txt
python -m pip install --upgrade -r doc/requirements.txt
python -m pip install --upgrade pip setuptools wheel invoke
- name: Build the Sphinx documentation
run: |
make -C doc html
invoke install doc.install doc.build
10 changes: 4 additions & 6 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
uses: actions/setup-python@v2
with:
python-version: '3.10'
- name: Install dependencies
- name: Install build tools
run: |
python -m pip install --upgrade pip setuptools wheel twine
- name: Build and publish
Expand All @@ -36,14 +36,12 @@ jobs:
uses: actions/setup-python@v2
with:
python-version: '3.10'
- name: Install dependencies
- name: Install build tools
run: |
python -m pip install --upgrade pip setuptools wheel
python -m pip install --upgrade -r requirements-dev.txt
python -m pip install --upgrade -r doc/requirements.txt
python -m pip install --upgrade pip setuptools wheel invoke
- name: Build the Sphinx documentation
run: |
make -C doc html
invoke install doc.install doc.build
- name: Deploy to GitHub Pages
if: success()
uses: peaceiris/actions-gh-pages@v3
Expand Down
14 changes: 0 additions & 14 deletions .github/workflows/release-drafter.yml

This file was deleted.

3 changes: 0 additions & 3 deletions .lvimrc

This file was deleted.

4 changes: 3 additions & 1 deletion MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
include README.md LICENSE.md pymapadmin/py.typed
include README.md LICENSE.md pyproject.toml pymapadmin/py.typed
recursive-include pymapadmin *.pyi
recursive-include test *.py
prune tasks
1 change: 0 additions & 1 deletion doc/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
sphinx
sphinx-autodoc-typehints
cloud_sptheme
15 changes: 14 additions & 1 deletion doc/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
'sphinx.ext.intersphinx',
'sphinx.ext.napoleon',
'sphinx.ext.githubpages',
'sphinx_autodoc_typehints',
'sphinx.ext.viewcode',
]

# Add any paths that contain templates here, relative to this directory.
Expand All @@ -70,10 +70,23 @@
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#
if csp.is_cloud_theme(html_theme):
html_theme_options = {
'borderless_decor': True,
'sidebarwidth': '3in',
'hyphenation_language': 'en',
}

# -- Extension configuration -------------------------------------------------

autodoc_member_order = 'bysource'
autodoc_default_flags = ['show-inheritance']
autodoc_typehints = 'description'
autodoc_typehints_format = 'short'
napoleon_numpy_docstring = False

# -- Options for intersphinx extension ---------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion pymapadmin/commands/health.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,10 @@ class CheckCommand(HealthCommand[HealthCheckRequest,
@classmethod
def add_subparser(cls, name: str, subparsers: Any) \
-> ArgumentParser: # pragma: no cover
return subparsers.add_parser(
argparser: ArgumentParser = subparsers.add_parser(
name, description=cls.__doc__,
help='check the server health')
return argparser

@property
def method(self) -> MethodProtocol[HealthCheckRequest,
Expand Down
2 changes: 1 addition & 1 deletion pymapadmin/commands/mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class AppendCommand(MailboxCommand[AppendRequest, AppendResponse]):
@classmethod
def add_subparser(cls, name: str, subparsers: Any) \
-> ArgumentParser: # pragma: no cover
subparser = subparsers.add_parser(
subparser: ArgumentParser = subparsers.add_parser(
name, description=cls.__doc__,
help='append a message to a mailbox')
subparser.add_argument('--from', metavar='ADDRESS', dest='sender',
Expand Down
7 changes: 4 additions & 3 deletions pymapadmin/commands/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class SaveArgsCommand(Command):
@classmethod
def add_subparser(cls, name: str, subparsers: Any) \
-> ArgumentParser: # pragma: no cover
subparser = subparsers.add_parser(
subparser: ArgumentParser = subparsers.add_parser(
name, description=cls.__doc__,
help='save connection arguments to config file')
return subparser
Expand All @@ -53,7 +53,7 @@ class LoginCommand(SystemCommand[LoginRequest, LoginResponse]):
@classmethod
def add_subparser(cls, name: str, subparsers: Any) \
-> ArgumentParser: # pragma: no cover
subparser = subparsers.add_parser(
subparser: ArgumentParser = subparsers.add_parser(
name, description=cls.__doc__,
help='login as a user')
subparser.add_argument('-s', '--save', action='store_true',
Expand Down Expand Up @@ -110,9 +110,10 @@ class PingCommand(SystemCommand[PingRequest, PingResponse]):
@classmethod
def add_subparser(cls, name: str, subparsers: Any) \
-> ArgumentParser: # pragma: no cover
return subparsers.add_parser(
argparser: ArgumentParser = subparsers.add_parser(
name, description=cls.__doc__,
help='ping the server')
return argparser

@property
def method(self) -> MethodProtocol[PingRequest, PingResponse]:
Expand Down
8 changes: 4 additions & 4 deletions pymapadmin/commands/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class GetUserCommand(UserCommand[GetUserRequest, UserResponse]):
@classmethod
def add_subparser(cls, name: str, subparsers: Any) \
-> ArgumentParser: # pragma: no cover
subparser = subparsers.add_parser(
subparser: ArgumentParser = subparsers.add_parser(
name, description=cls.__doc__,
help='get a user')
subparser.add_argument('username', help='the user name')
Expand All @@ -48,7 +48,7 @@ class SetUserCommand(UserCommand[SetUserRequest, UserResponse]):
@classmethod
def add_subparser(cls, name: str, subparsers: Any) \
-> ArgumentParser: # pragma: no cover
subparser = subparsers.add_parser(
subparser: ArgumentParser = subparsers.add_parser(
name, description=cls.__doc__,
help='assign a password to a user')
subparser.add_argument('--password-file', type=FileType('r'),
Expand All @@ -70,7 +70,7 @@ def getpass(self) -> str | None:
if self.args.no_password:
return None
elif self.args.password_file:
line = self.args.password_file.readline()
line: str = self.args.password_file.readline()
return line.rstrip('\r\n')
else:
return getpass.getpass()
Expand Down Expand Up @@ -100,7 +100,7 @@ class DeleteUserCommand(UserCommand[DeleteUserRequest, UserResponse]):
@classmethod
def add_subparser(cls, name: str, subparsers: Any) \
-> ArgumentParser: # pragma: no cover
subparser = subparsers.add_parser(
subparser: ArgumentParser = subparsers.add_parser(
name, description=cls.__doc__,
help='delete a user')
subparser.add_argument('username', help='the user name')
Expand Down
5 changes: 3 additions & 2 deletions pymapadmin/local.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@

class _AddAction(Action):

def __init__(self, local_file: LocalFile, *args, **kwargs) -> None:
def __init__(self, local_file: LocalFile,
*args: Any, **kwargs: Any) -> None:
kwargs['metavar'] = 'PATH'
super().__init__(*args, **kwargs)
self._local_file = local_file

def __call__(self, parser: ArgumentParser, namespace: Namespace,
values: Any, option_string: str = None) -> None:
values: Any, option_string: str | None = None) -> None:
setattr(namespace, self.dest, values)
self._local_file.add(values)

Expand Down
25 changes: 25 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[build-system]
requires = ['setuptools', 'wheel']

[tool.mypy]
strict = true
files = ['pymapadmin', 'test']

[[tool.mypy.overrides]]
module = 'google.rpc.*'
ignore_missing_imports = true

[tool.pytest.ini_options]
testpaths = 'test'
asyncio_mode = 'auto'
norecursedirs = 'doc'

[tool.coverage.report]
fail_under = 90
omit = ['*/main.py', '*/config.py', '*/local.py', '*/grpc/*']
exclude_lines = [
'pragma: no cover',
'NotImplemented',
'^\s*...\s*$',
'def __repr__',
]
3 changes: 2 additions & 1 deletion requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ autopep8
pytest
pytest-asyncio
pytest-cov
bandit[toml]
rope

# unreleased typing changes
grpclib == 0.4.3rc1
grpclib == 0.4.3rc2

# stubs
types-setuptools
Expand Down
14 changes: 0 additions & 14 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,16 +1,2 @@
[mypy]
files = pymapadmin, test
ignore_missing_imports = True

[flake8]
exclude = pymapadmin/grpc

[tool:pytest]
asyncio_mode = auto

[coverage:report]
omit = */main.py, */config.py, */local.py, */grpc/*
exclude_lines =
pragma: no cover
NotImplementedError
^\s*...\s*$
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
'Programming Language :: Python :: 3.10'],
python_requires='~=3.10',
include_package_data=True,
packages=find_packages(),
packages=find_packages(include=('pymapadmin', 'pymapadmin.*')),
install_requires=[
'grpclib', 'protobuf', 'typing-extensions'],
extras_require={
Expand Down
65 changes: 65 additions & 0 deletions tasks/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# type: ignore

import os
import os.path
from shlex import join
from invoke import task, Collection

from . import check, doc, lint, test, types


@task
def clean(ctx, full=False):
"""Delete all the standard build and validate artifacts."""
if full:
ctx.run('git clean -dfX')
else:
anywhere = ['__pycache__']
top_level = [
'.coverage',
'.mypy_cache',
'.pytest_cache',
'dist',
'doc/build/']
for name in anywhere:
for path in [ctx.package, 'test']:
subpaths = [os.path.join(subpath, name)
for subpath, dirs, names in os.walk(path)
if name in dirs or name in names]
for subpath in subpaths:
ctx.run(join(['rm', '-rf', subpath]))
for name in top_level:
ctx.run(join(['rm', '-rf', name]))


@task
def install(ctx, dev=True, update=False):
"""Install the library and all development tools."""
choice = 'dev' if dev else 'all'
if update:
ctx.run('pip install -U -r requirements-{}.txt'.format(choice))
else:
ctx.run('pip install -r requirements-{}.txt'.format(choice))


@task(test.all, types.all, lint.all)
def validate(ctx):
"""Run all tests, type checks, and linters."""
pass


ns = Collection(clean, install)
ns.add_task(validate, default=True)
ns.add_collection(check)
ns.add_collection(test)
ns.add_collection(types)
ns.add_collection(lint)
ns.add_collection(doc)

ns.configure({
'package': 'pymapadmin',
'run': {
'echo': True,
'pty': True,
}
})
19 changes: 19 additions & 0 deletions tasks/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# type: ignore

import warnings

from invoke import task, Collection


@task
def check_import(ctx):
"""Check that the library can be imported."""
try:
__import__(ctx.package)
except Exception:
warnings.warn('Could not import {!r}, '
'task may fail'.format(ctx.package))


ns = Collection()
ns.add_task(check_import, default=True)
Loading

0 comments on commit 10d7e6b

Please sign in to comment.