Skip to content

Commit a70bba0

Browse files
Add type hints and MyPy checking to CI (#69)
* Add type hints and MyPy checking to CI - Added MyPy as a dependency - Added MyPy GitHub Actions workflow - Added type hints to all Python files - Added `type: ignore` comments for libraries without type stubs * Update environment.yml * Update mypy.yml * Update _version.py * Update share.py * Update pyproject.toml * Update test_cmd.py * Update test_cmd.py * Update test_core.py * Update test_user_interface.py * Update test_share.py * Update test_share.py * Create .pre-commit-config.yaml * black formatting * Delete .github/workflows/mypy.yml * Merge CI * Delete .pre-commit-config.yaml * fixes --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 2aafb87 commit a70bba0

9 files changed

Lines changed: 155 additions & 133 deletions

File tree

.github/workflows/black.yml

Lines changed: 0 additions & 18 deletions
This file was deleted.

.github/workflows/coverage.yml

Lines changed: 0 additions & 34 deletions
This file was deleted.

.github/workflows/pipeline.yml

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
name: Pipeline
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
8+
jobs:
9+
black:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
- uses: psf/black@stable
14+
with:
15+
options: "--check --diff"
16+
src: ./${{ github.event.repository.name }}
17+
18+
black_fix: # in most cases pre-commit is faster
19+
needs: [black]
20+
if: failure()
21+
runs-on: ubuntu-latest
22+
steps:
23+
- uses: actions/checkout@v4
24+
with:
25+
token: ${{ secrets.DEPENDABOT_WORKFLOW_TOKEN }}
26+
ref: ${{ github.event.pull_request.head.ref }} # Check out the head of the actual branch, not the PR
27+
fetch-depth: 0 # otherwise, you will fail to push refs to dest repo
28+
- name: format black
29+
uses: psf/black@stable
30+
with:
31+
options: ""
32+
src: "./${{ github.event.repository.name }}"
33+
- name: commit
34+
run: |
35+
git config --local user.email "pyiron@mpie.de"
36+
git config --local user.name "pyiron-runner"
37+
git commit -m "Format black" -a
38+
- name: push
39+
uses: ad-m/github-push-action@master
40+
with:
41+
github_token: ${{ secrets.DEPENDABOT_WORKFLOW_TOKEN }}
42+
branch: ${{ github.event.pull_request.head.ref }}
43+
44+
mypy:
45+
needs: [black]
46+
runs-on: ubuntu-latest
47+
steps:
48+
- name: Setup Python
49+
uses: actions/setup-python@v5
50+
with:
51+
python-version: "3.13"
52+
architecture: x64
53+
- name: Checkout
54+
uses: actions/checkout@v4
55+
- name: Install mypy
56+
run: pip install mypy
57+
- name: Test
58+
run: mypy --ignore-missing-imports ${{ github.event.repository.name }}
59+
60+
pip_check:
61+
needs: [black]
62+
runs-on: ubuntu-latest
63+
steps:
64+
- uses: actions/checkout@v4
65+
- name: Conda config
66+
run: echo -e "channels:\n - conda-forge\n" > .condarc
67+
- uses: conda-incubator/setup-miniconda@v3
68+
with:
69+
python-version: "3.13"
70+
miniforge-version: latest
71+
condarc-file: .condarc
72+
environment-file: .ci_support/environment.yml
73+
- name: Setup
74+
shell: bash -l {0}
75+
run: |
76+
pip install tomlkit
77+
pip install . --no-deps --no-build-isolation
78+
pip check
79+
80+
unittest:
81+
needs: [black]
82+
runs-on: ${{ matrix.operating-system }}
83+
strategy:
84+
matrix:
85+
operating-system: [ubuntu-latest, macos-latest]
86+
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13']
87+
steps:
88+
- uses: actions/checkout@v4
89+
- name: Conda config
90+
shell: bash -l {0}
91+
run: echo -e "channels:\n - conda-forge\n" > .condarc
92+
- uses: conda-incubator/setup-miniconda@v3
93+
with:
94+
python-version: ${{ matrix.python-version }}
95+
miniforge-version: latest
96+
condarc-file: .condarc
97+
environment-file: .ci_support/environment.yml
98+
- name: Test
99+
shell: bash -l {0}
100+
run: |
101+
pip install --no-deps .
102+
coverage run -a -m unittest discover tests
103+
104+
coverage:
105+
needs: [black]
106+
runs-on: ubuntu-latest
107+
steps:
108+
- uses: actions/checkout@v4
109+
- name: Conda config
110+
shell: bash -l {0}
111+
run: echo -e "channels:\n - conda-forge\n" > .condarc
112+
- uses: conda-incubator/setup-miniconda@v3
113+
with:
114+
python-version: '3.13'
115+
miniforge-version: latest
116+
condarc-file: .condarc
117+
environment-file: .ci_support/environment.yml
118+
- name: Test
119+
shell: bash -l {0}
120+
run: |
121+
pip install --no-deps .
122+
coverage run -a -m unittest discover tests
123+
coverage combine
124+
coverage xml
125+
- name: Coveralls
126+
uses: coverallsapp/github-action@v2

.github/workflows/pypicheck.yml

Lines changed: 0 additions & 27 deletions
This file was deleted.

.github/workflows/unittest.yml

Lines changed: 0 additions & 36 deletions
This file was deleted.

pyauthenticator/__init__.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22
Generate two factor authentication codes on the command line
33
"""
44

5+
from typing import Optional
56
from . import _version
67
from pyauthenticator.share import generate_qrcode
78
from pyauthenticator.share import get_two_factor_code as get_two_factor_code_internal
89
from pyauthenticator.share import load_config
910

10-
__version__ = _version.__version__
11+
__version__: str = _version.__version__
1112

1213

13-
def write_qrcode_to_file(service, file_name=None):
14+
def write_qrcode_to_file(service: str, file_name: Optional[str] = None) -> None:
1415
"""
1516
Write qrcode to file to scan it with a mobile application
1617
@@ -21,7 +22,7 @@ def write_qrcode_to_file(service, file_name=None):
2122
generate_qrcode(key=service, config_dict=load_config(), file_name=file_name)
2223

2324

24-
def get_two_factor_code(service):
25+
def get_two_factor_code(service: str) -> str:
2526
"""
2627
Generate two factor authentication code
2728

pyauthenticator/__main__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import argparse
66
import sys
7+
from typing import Optional, Sequence
78

89
from pyauthenticator.share import (
910
add_service,
@@ -14,7 +15,7 @@
1415
)
1516

1617

17-
def command_line_parser(cmd_args=None):
18+
def command_line_parser(cmd_args: Optional[Sequence[str]] = None) -> None:
1819
"""
1920
Main function primarly used for the command line interface
2021
"""

pyauthenticator/share.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,18 @@
55
import json
66
import os
77
from inspect import signature
8+
from typing import Any, Dict, List, Optional
89

910
import pyotp
1011
import qrcode
1112
from PIL import Image
1213
from pyzbar.pyzbar import decode
1314

1415
# default configuration file
15-
config_file = "~/.pyauthenticator"
16+
config_file: str = "~/.pyauthenticator"
1617

1718

18-
def expand_path(path):
19+
def expand_path(path: str) -> str:
1920
"""
2021
Expand path by expanding the user variable and converting the path to an absolute path
2122
@@ -28,7 +29,7 @@ def expand_path(path):
2829
return os.path.abspath(os.path.expanduser(path))
2930

3031

31-
def load_config(config_file_to_load=config_file):
32+
def load_config(config_file_to_load: str = config_file) -> Dict[str, Any]:
3233
"""
3334
Load configuration file
3435
@@ -46,7 +47,9 @@ def load_config(config_file_to_load=config_file):
4647
return {}
4748

4849

49-
def write_config(config_dict, config_file_to_write=config_file):
50+
def write_config(
51+
config_dict: Dict[str, Any], config_file_to_write: str = config_file
52+
) -> None:
5053
"""
5154
Write configuration file
5255
@@ -58,7 +61,7 @@ def write_config(config_dict, config_file_to_write=config_file):
5861
json.dump(config_dict, f)
5962

6063

61-
def get_otpauth_dict(otpauth_str):
64+
def get_otpauth_dict(otpauth_str: str) -> Dict[str, str]:
6265
"""
6366
Parse otpauth url
6467
@@ -76,7 +79,7 @@ def get_otpauth_dict(otpauth_str):
7679
}
7780

7881

79-
def check_if_key_in_config(key, config_dict):
82+
def check_if_key_in_config(key: str, config_dict: Dict[str, Any]) -> None:
8083
"""
8184
Check if a given key is included in a dictionary, raise an ValueError if it is not.
8285
@@ -88,7 +91,7 @@ def check_if_key_in_config(key, config_dict):
8891
raise ValueError()
8992

9093

91-
def get_two_factor_code(key, config_dict):
94+
def get_two_factor_code(key: str, config_dict: Dict[str, Any]) -> str:
9295
"""
9396
Generate the two factor authentication code
9497
@@ -123,8 +126,11 @@ def get_two_factor_code(key, config_dict):
123126

124127

125128
def add_service(
126-
key, qrcode_png_file_name, config_dict, config_file_to_write=config_file
127-
):
129+
key: str,
130+
qrcode_png_file_name: str,
131+
config_dict: Dict[str, Any],
132+
config_file_to_write: str = config_file,
133+
) -> None:
128134
"""
129135
Add new service to configuration file
130136
@@ -139,7 +145,9 @@ def add_service(
139145
write_config(config_dict=config_dict, config_file_to_write=config_file_to_write)
140146

141147

142-
def generate_qrcode(key, config_dict, file_name=None):
148+
def generate_qrcode(
149+
key: str, config_dict: Dict[str, Any], file_name: Optional[str] = None
150+
) -> None:
143151
"""
144152
Write qrcode to file to scan it with a mobile application
145153
@@ -154,7 +162,7 @@ def generate_qrcode(key, config_dict, file_name=None):
154162
qrcode.make(config_dict[key]).save(file_name, "PNG")
155163

156164

157-
def list_services(config_dict):
165+
def list_services(config_dict: Dict[str, Any]) -> List[str]:
158166
"""
159167
List available services
160168

0 commit comments

Comments
 (0)