Skip to content

Commit 67e6191

Browse files
authored
Added type hinting (equinor#195)
1 parent 711fd4f commit 67e6191

31 files changed

+217
-169
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
.eggs
22
*.egg-info
3+
*~
4+
.mypy_cache
35
__pycache__
46
node_modules
57
venv

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ script:
3535
- black --check webviz_config tests setup.py
3636
- pylint webviz_config tests setup.py
3737
- bandit -r -c ./bandit.yml webviz_config tests setup.py
38+
- mypy --package webviz_config --ignore-missing-imports --disallow-untyped-defs --show-error-codes
3839

3940
- webviz certificate
4041
- pytest tests --forked

setup.py

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"pytest-xdist",
1111
"black",
1212
"bandit",
13+
"mypy",
1314
]
1415

1516
setup(

webviz_config/_build_webviz.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import shutil
44
import tempfile
55
import subprocess # nosec
6+
import argparse
67

78
from yaml import YAMLError
89

@@ -15,7 +16,7 @@
1516
STATIC_FOLDER = os.path.join(os.path.dirname(__file__), "static")
1617

1718

18-
def build_webviz(args):
19+
def build_webviz(args: argparse.Namespace) -> None:
1920

2021
if args.theme not in installed_themes:
2122
raise ValueError(f"Theme `{args.theme}` is not installed.")
@@ -87,7 +88,7 @@ def build_webviz(args):
8788
shutil.rmtree(build_directory)
8889

8990

90-
def run_webviz(args, build_directory):
91+
def run_webviz(args: argparse.Namespace, build_directory: str) -> None:
9192

9293
print(
9394
f"{terminal_colors.YELLOW}"

webviz_config/_certificate.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import getpass
66
import datetime
77
import subprocess # nosec
8+
import argparse
89

910
from cryptography import x509
1011
from cryptography.x509.oid import NameOID
@@ -32,7 +33,7 @@
3233
SERVER_CRT_FILENAME = "server.crt"
3334

3435

35-
def user_data_dir():
36+
def user_data_dir() -> str:
3637
"""Returns platform specific path to store user application data
3738
"""
3839

@@ -45,7 +46,7 @@ def user_data_dir():
4546
return os.path.expanduser("~/.local/share/webviz")
4647

4748

48-
def create_key(key_path):
49+
def create_key(key_path: str) -> rsa.RSAPrivateKey:
4950

5051
key = rsa.generate_private_key(
5152
public_exponent=65537, key_size=2048, backend=default_backend()
@@ -63,7 +64,12 @@ def create_key(key_path):
6364
return key
6465

6566

66-
def certificate_template(subject, issuer, public_key, certauthority=False):
67+
def certificate_template(
68+
subject: x509.name.Name,
69+
issuer: x509.name.Name,
70+
public_key: x509.name.Name,
71+
certauthority: bool = False,
72+
) -> x509.base.CertificateBuilder:
6773

6874
if certauthority:
6975
not_valid_after = datetime.datetime.utcnow() + datetime.timedelta(days=365 * 10)
@@ -88,7 +94,7 @@ def certificate_template(subject, issuer, public_key, certauthority=False):
8894
)
8995

9096

91-
def create_ca(args):
97+
def create_ca(args: argparse.Namespace) -> None:
9298

9399
directory = user_data_dir()
94100

@@ -180,8 +186,7 @@ def create_ca(args):
180186
)
181187

182188

183-
def create_certificate(directory):
184-
189+
def create_certificate(directory: str) -> None:
185190
ca_directory = user_data_dir()
186191
ca_key_path = os.path.join(ca_directory, CA_KEY_FILENAME)
187192
ca_crt_path = os.path.join(ca_directory, CA_CRT_FILENAME)

webviz_config/_config_parser.py

+20-19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import inspect
55
import importlib
66
import typing
7+
import types
78
import warnings
89

910
import yaml
@@ -16,26 +17,26 @@
1617
SPECIAL_ARGS = ["self", "app", "container_settings", "_call_signature", "_imports"]
1718

1819

19-
def _get_webviz_plugins(module):
20+
def _get_webviz_plugins(module: types.ModuleType) -> list:
2021
"""Returns a list of all Webviz plugins
2122
in the module given as input.
2223
"""
2324

24-
def _is_webviz_plugin(obj):
25+
def _is_webviz_plugin(obj: typing.Any) -> bool:
2526
return inspect.isclass(obj) and issubclass(obj, WebvizPluginABC)
2627

2728
return [member[0] for member in inspect.getmembers(module, _is_webviz_plugin)]
2829

2930

3031
def _call_signature(
31-
module,
32-
module_name,
33-
plugin_name,
34-
shared_settings,
35-
kwargs,
36-
config_folder,
37-
contact_person=None,
38-
):
32+
module: types.ModuleType,
33+
module_name: str,
34+
plugin_name: str,
35+
shared_settings: dict,
36+
kwargs: dict,
37+
config_folder: pathlib.Path,
38+
contact_person: typing.Optional[dict] = None,
39+
) -> tuple:
3940
# pylint: disable=too-many-branches,too-many-statements
4041
"""Takes as input the name of a plugin, the module it is located in,
4142
together with user given arguments (originating from the configuration
@@ -158,7 +159,7 @@ class ConfigParser:
158159

159160
STANDARD_PLUGINS = _get_webviz_plugins(standard_plugins)
160161

161-
def __init__(self, yaml_file):
162+
def __init__(self, yaml_file: str):
162163

163164
ConfigParser.check_for_tabs_in_file(yaml_file)
164165

@@ -181,12 +182,12 @@ def __init__(self, yaml_file):
181182
).with_traceback(sys.exc_info()[2])
182183

183184
self._config_folder = pathlib.Path(yaml_file).parent
184-
self._page_ids = []
185-
self._assets = set()
185+
self._page_ids: typing.List[str] = []
186+
self._assets: set = set()
186187
self.clean_configuration()
187188

188189
@staticmethod
189-
def check_for_tabs_in_file(path):
190+
def check_for_tabs_in_file(path: str) -> None:
190191

191192
with open(path, "r") as filehandle:
192193
# Create a list with unique entries of line numbers containing tabs
@@ -209,7 +210,7 @@ def check_for_tabs_in_file(path):
209210
f"{terminal_colors.END}"
210211
)
211212

212-
def _generate_page_id(self, title):
213+
def _generate_page_id(self, title: str) -> str:
213214
"""From the user given title, this function provides a unique
214215
human readable page id, not already present in self._page_ids
215216
"""
@@ -225,7 +226,7 @@ def _generate_page_id(self, title):
225226

226227
return page_id
227228

228-
def clean_configuration(self):
229+
def clean_configuration(self) -> None:
229230
# pylint: disable=too-many-branches,too-many-statements
230231
"""Various cleaning and checks of the raw configuration read
231232
from the user provided yaml configuration file.
@@ -372,13 +373,13 @@ def clean_configuration(self):
372373
self.assets.update(getattr(module, plugin_name).ASSETS)
373374

374375
@property
375-
def configuration(self):
376+
def configuration(self) -> dict:
376377
return self._configuration
377378

378379
@property
379-
def shared_settings(self):
380+
def shared_settings(self) -> dict:
380381
return self._shared_settings
381382

382383
@property
383-
def assets(self):
384+
def assets(self) -> set:
384385
return self._assets

webviz_config/_is_reload_process.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22

33

4-
def is_reload_process():
4+
def is_reload_process() -> bool:
55
"""Within the flask reload machinery, it is not straight forward to know
66
if the code is run as the main process (i.e. the process the user directly
77
started), or if the code is a "hot reload process" (see Flask

webviz_config/_localhost_certificate.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ class LocalhostCertificate:
1313
only readable by the user running the process, and are deleted on exit.
1414
"""
1515

16-
def __init__(self):
16+
def __init__(self) -> None:
1717
if not is_reload_process():
1818
self._ssl_temp_dir = os.environ["WEBVIZ_SSL_TEMP_DIR"] = tempfile.mkdtemp()
1919
create_certificate(self._ssl_temp_dir)
2020
atexit.register(self._delete_temp_dir)
2121
else:
2222
self._ssl_temp_dir = os.environ["WEBVIZ_SSL_TEMP_DIR"]
2323

24-
def _delete_temp_dir(self):
24+
def _delete_temp_dir(self) -> None:
2525
"""Delete temporary directory with on-the-fly generated localhost certificates
2626
"""
2727
shutil.rmtree(self._ssl_temp_dir)
2828

2929
@property
30-
def ssl_context(self):
30+
def ssl_context(self) -> tuple:
3131
return (
3232
os.path.join(self._ssl_temp_dir, SERVER_CRT_FILENAME),
3333
os.path.join(self._ssl_temp_dir, SERVER_KEY_FILENAME),

webviz_config/_localhost_open_browser.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,15 @@
1111
class LocalhostOpenBrowser:
1212
# pylint: disable=too-few-public-methods
1313

14-
def __init__(self, port, token):
14+
def __init__(self, port: int, token: str):
1515
self._port = port
1616
self._token = token
1717

1818
if not is_reload_process():
1919
# Only open new browser tab if not a reload process
2020
threading.Thread(target=self._timer).start()
2121

22-
def _timer(self):
22+
def _timer(self) -> None:
2323
"""Waits until the app is ready, and then opens the page
2424
in the default browser.
2525
"""
@@ -39,14 +39,14 @@ def _timer(self):
3939
f"{self._url(with_token=True)}"
4040
)
4141

42-
def _url(self, with_token=False, https=True):
42+
def _url(self, with_token: bool = False, https: bool = True) -> str:
4343
return (
4444
f"{'https' if https else 'http'}://localhost:{self._port}"
4545
+ f"{'?ott=' + self._token if with_token else ''}"
4646
)
4747

4848
@staticmethod
49-
def _get_browser_controller():
49+
def _get_browser_controller() -> webbrowser.BaseBrowser:
5050
for browser in ["chrome", "chromium-browser"]:
5151
try:
5252
return webbrowser.get(using=browser)
@@ -57,7 +57,7 @@ def _get_browser_controller():
5757
# preferred browsers are installed:
5858
return webbrowser.get()
5959

60-
def _app_ready(self):
60+
def _app_ready(self) -> bool:
6161
"""Check if the flask instance is ready.
6262
"""
6363

@@ -67,7 +67,7 @@ def _app_ready(self):
6767
try:
6868
urllib.request.urlopen(self._url(https=False)) # nosec
6969
app_ready = True
70-
except urllib.error.URLError:
70+
except urllib.error.URLError: # type: ignore[attr-defined]
7171
# The flask instance has not started
7272
app_ready = False
7373
except ConnectionResetError:
@@ -79,7 +79,7 @@ def _app_ready(self):
7979

8080
return app_ready
8181

82-
def _open_new_tab(self):
82+
def _open_new_tab(self) -> None:
8383
"""Open the url (with token) in the default browser.
8484
"""
8585

webviz_config/_localhost_token.py

+8-6
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class LocalhostToken:
3030
two different localhost applications running simultaneously do not interfere.
3131
"""
3232

33-
def __init__(self, app, port):
33+
def __init__(self, app: flask.app.Flask, port: int):
3434
self._app = app
3535
self._port = port
3636

@@ -53,17 +53,17 @@ def __init__(self, app, port):
5353
self.set_request_decorators()
5454

5555
@staticmethod
56-
def generate_token():
56+
def generate_token() -> str:
5757
return secrets.token_urlsafe(nbytes=64)
5858

5959
@property
60-
def one_time_token(self):
60+
def one_time_token(self) -> str:
6161
return self._ott
6262

63-
def set_request_decorators(self):
63+
def set_request_decorators(self) -> None:
6464
# pylint: disable=inconsistent-return-statements
6565
@self._app.before_request
66-
def _check_for_ott_or_cookie():
66+
def _check_for_ott_or_cookie(): # type: ignore[no-untyped-def]
6767
if not self._ott_validated and self._ott == flask.request.args.get("ott"):
6868
self._ott_validated = True
6969
flask.g.set_cookie_token = True
@@ -77,7 +77,9 @@ def _check_for_ott_or_cookie():
7777
flask.abort(401)
7878

7979
@self._app.after_request
80-
def _set_cookie_token_in_response(response):
80+
def _set_cookie_token_in_response(
81+
response: flask.wrappers.Response,
82+
) -> flask.wrappers.Response:
8183
if "set_cookie_token" in flask.g and flask.g.set_cookie_token:
8284
response.set_cookie(
8385
key=f"cookie_token_{self._port}", value=self._cookie_token

0 commit comments

Comments
 (0)