Skip to content

Commit

Permalink
Add type annotations (#341)
Browse files Browse the repository at this point in the history
- Annotate the package.
- Annotate the tests.
- Run mypy in CI (in both Python 2 and Python 3 modes).
- Publish the types with `py.typed` files.
  • Loading branch information
bluetech committed Aug 8, 2021
1 parent a411dad commit 5131f79
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 29 deletions.
1 change: 1 addition & 0 deletions .coveragerc
Expand Up @@ -7,3 +7,4 @@ omit=
precision = 1
exclude_lines =
pragma: no cover
if TYPE_CHECKING:
22 changes: 22 additions & 0 deletions .github/workflows/lint.yml
@@ -0,0 +1,22 @@
name: Lint

on:
push:
branches-ignore:
- "dependabot/**"
pull_request:

jobs:
Lint:
name: 'Lint'
timeout-minutes: 10
runs-on: 'ubuntu-latest'
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Run lint
run: ./lint.sh
6 changes: 6 additions & 0 deletions lint-requirements.in
@@ -0,0 +1,6 @@
# Typing
mypy[python2]==0.910
# TODO: Switch to cryptography>=35.0.0 once it's released.
types-cryptography>=3.3.3
types-pyopenssl>=20.0.4
py>=1.9.0
28 changes: 28 additions & 0 deletions lint-requirements.txt
@@ -0,0 +1,28 @@
#
# This file is autogenerated by pip-compile with python 3.9
# To update, run:
#
# pip-compile lint-requirements.in
#
mypy[python2]==0.910
# via -r lint-requirements.in
mypy-extensions==0.4.3
# via mypy
py==1.10.0
# via -r lint-requirements.in
toml==0.10.2
# via mypy
typed-ast==1.4.3
# via mypy
types-cryptography==3.3.3
# via
# -r lint-requirements.in
# types-pyopenssl
types-enum34==0.1.8
# via types-cryptography
types-ipaddress==0.1.5
# via types-cryptography
types-pyopenssl==20.0.4
# via -r lint-requirements.in
typing-extensions==3.10.0.0
# via mypy
17 changes: 17 additions & 0 deletions lint.sh
@@ -0,0 +1,17 @@
#!/bin/bash

set -exu -o pipefail

python -c "import sys, struct, ssl; print('#' * 70); print('python:', sys.version); print('version_info:', sys.version_info); print('bits:', struct.calcsize('P') * 8); print('openssl:', ssl.OPENSSL_VERSION, ssl.OPENSSL_VERSION_INFO); print('#' * 70)"

python -m pip install -U pip setuptools wheel
python -m pip --version

# Dependencies

python -m pip install -Ur lint-requirements.txt

# Linting

mypy trustme tests
mypy -2 trustme tests
1 change: 1 addition & 0 deletions newsfragments/339.feature.rst
@@ -0,0 +1 @@
The package is now type annotated. If you use mypy on code which uses ``trustme``, you should be able to remove any exclusions.
23 changes: 23 additions & 0 deletions pyproject.toml
Expand Up @@ -17,3 +17,26 @@ directory = "newsfragments"
underlines = ["-", "~", "^"]
# Requires https://github.com/hawkowl/towncrier/pull/66
issue_format = "`#{issue} <https://github.com/python-trio/trustme/issues/{issue}>`__"

[tool.mypy]
check_untyped_defs = true
disallow_any_generics = true
disallow_incomplete_defs = true
disallow_subclassing_any = true
disallow_untyped_calls = true
disallow_untyped_decorators = true
disallow_untyped_defs = true
no_implicit_optional = true
no_implicit_reexport = true
show_error_codes = true
strict_equality = true
warn_redundant_casts = true
warn_return_any = true
warn_unreachable = true
warn_unused_configs = true
# Some ignores are only for python2/python3.
# warn_unused_ignores = true

[[tool.mypy.overrides]]
module = "pytest"
ignore_missing_imports = true
3 changes: 3 additions & 0 deletions setup.py
Expand Up @@ -13,6 +13,9 @@
author_email="njs@pobox.com",
license="MIT -or- Apache License 2.0",
packages=find_packages(),
package_data={
'trustme': ['py.typed'],
},
url="https://github.com/python-trio/trustme",
install_requires=[
"cryptography",
Expand Down
15 changes: 15 additions & 0 deletions tests/test_cli.py
Expand Up @@ -3,12 +3,18 @@
import subprocess
import sys

import py
import pytest

from trustme._cli import main

TYPE_CHECKING = False
if TYPE_CHECKING: # pragma: no cover
from typing import Any


def test_trustme_cli(tmpdir):
# type: (py.path.local) -> None
with tmpdir.as_cwd():
main(argv=[])

Expand All @@ -18,6 +24,7 @@ def test_trustme_cli(tmpdir):


def test_trustme_cli_e2e(tmpdir):
# type: (py.path.local) -> None
with tmpdir.as_cwd():
rv = subprocess.call([sys.executable, "-m", "trustme"])
assert rv == 0
Expand All @@ -28,6 +35,7 @@ def test_trustme_cli_e2e(tmpdir):


def test_trustme_cli_directory(tmpdir):
# type: (py.path.local) -> None
subdir = tmpdir.mkdir("sub")
main(argv=["-d", str(subdir)])

Expand All @@ -37,12 +45,14 @@ def test_trustme_cli_directory(tmpdir):


def test_trustme_cli_directory_does_not_exist(tmpdir):
# type: (py.path.local) -> None
notdir = tmpdir.join("notdir")
with pytest.raises(ValueError, match="is not a directory"):
main(argv=["-d", str(notdir)])


def test_trustme_cli_identities(tmpdir):
# type: (py.path.local) -> None
with tmpdir.as_cwd():
main(argv=["-i", "example.org", "www.example.org"])

Expand All @@ -52,11 +62,13 @@ def test_trustme_cli_identities(tmpdir):


def test_trustme_cli_identities_empty(tmpdir):
# type: (py.path.local) -> None
with pytest.raises(ValueError, match="at least one identity"):
main(argv=["-i"])


def test_trustme_cli_common_name(tmpdir):
# type: (py.path.local) -> None
with tmpdir.as_cwd():
main(argv=["--common-name", "localhost"])

Expand All @@ -66,6 +78,7 @@ def test_trustme_cli_common_name(tmpdir):


def test_trustme_cli_expires_on(tmpdir):
# type: (py.path.local) -> None
with tmpdir.as_cwd():
main(argv=["--expires-on", "2035-03-01"])

Expand All @@ -75,6 +88,7 @@ def test_trustme_cli_expires_on(tmpdir):


def test_trustme_cli_invalid_expires_on(tmpdir):
# type: (py.path.local) -> None
with tmpdir.as_cwd():
with pytest.raises(ValueError, match="does not match format"):
main(argv=["--expires-on", "foobar"])
Expand All @@ -85,6 +99,7 @@ def test_trustme_cli_invalid_expires_on(tmpdir):


def test_trustme_cli_quiet(capsys, tmpdir):
# type: (Any, py.path.local) -> None
with tmpdir.as_cwd():
main(argv=["-q"])

Expand Down

0 comments on commit 5131f79

Please sign in to comment.