Skip to content

Commit d1f030d

Browse files
authored
chore: add mypy and update type hints across codebase (#54)
- Update type hints throughout codebase - Configure mypy for type checking - Add type checking to CI pipeline and documentation
1 parent ce10252 commit d1f030d

File tree

7 files changed

+57
-24
lines changed

7 files changed

+57
-24
lines changed

.github/workflows/pr_checks.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
- name: 'Ruff Check'
2828
run: |
2929
ruff check --output-format=github
30+
- name: 'MyPy Check'
31+
run: |
32+
mypy st_link_analysis/
3033
3134
lint_js:
3235
runs-on: ubuntu-latest

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
1010
Thanks to @drachenbach for the PR. ([#39](https://github.com/AlrasheedA/st-link-analysis/pull/39))
1111
- 9 new Material icons to frontend assets. ([#47](https://github.com/AlrasheedA/st-link-analysis/pull/47))
1212
- Support for dynamically loading debug pages from the `examples/debug/` directory in demo's `app.py`
13+
- Added mypy in the development workflow. Updated type hints throughout the codebase.
1314

1415
### Fixed
1516
- Prevent accumulating multiple `.svg` extensions on repeated calls of `dump`

README.md

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ A demo deployed with Render can be [accessed here](https://st-link-analysis-demo
2626
- View control bar for zooming, fitting, and centering the view, making it easier to navigate your graphs.
2727
- View all properties of the selected elements in a side panel.
2828
- Highlights neighboring nodes or edges when an element is selected.
29-
- **Node Actions (Expand / Remove):** Enable node removal and expansion using the `node_actions` parameter. Removal can be triggered by a delete keydown or a remove button click, while expansion occurs on a double-click or expand button click. When these events are triggered, the event details and selected node IDs are sent back to the Streamlit app as the components return value.
29+
- **Node Actions (Expand / Remove):** Enable node removal and expansion using the `node_actions` parameter. Removal can be triggered by a delete keydown or a remove button click, while expansion occurs on a double-click or expand button click. When these events are triggered, the event details and selected node IDs are sent back to the Streamlit app as the component's return value.
3030

3131
## Installation
3232

@@ -136,13 +136,24 @@ streamlit run app.py
136136

137137
### Testing
138138

139-
Run linting and tests:
139+
Run linting, type checking, and tests:
140140

141141
```bash
142142
ruff check
143+
mypy st_link_analysis/
143144
pytest
144145
```
145146

147+
### Type Checking
148+
149+
This project uses type hints and mypy for static type checking to improve code maintainability and developer experience. The mypy configuration is defined in `pyproject.toml` with strict settings to catch potential type-related issues early.
150+
151+
To run type checking locally:
152+
153+
```bash
154+
mypy st_link_analysis/
155+
```
156+
146157
## Contributing
147158

148159
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.

pyproject.toml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,21 @@ indent-width = 4
4141
select = ["E4", "E7", "E9", "F"]
4242
fixable = ["ALL"]
4343

44+
[tool.mypy]
45+
python_version = "3.9"
46+
warn_return_any = true
47+
warn_unused_configs = true
48+
disallow_untyped_defs = true
49+
disallow_incomplete_defs = true
50+
check_untyped_defs = true
51+
disallow_untyped_decorators = true
52+
no_implicit_optional = true
53+
warn_redundant_casts = true
54+
warn_unused_ignores = true
55+
warn_no_return = true
56+
warn_unreachable = true
57+
strict_equality = true
58+
4459
[tool.pytest.ini_options]
4560
addopts = "--reruns=3"
4661

@@ -50,4 +65,5 @@ dev = [
5065
"pytest",
5166
"pytest-playwright",
5267
"pytest-rerunfailures",
68+
"mypy",
5369
]

st_link_analysis/component/component.py

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import os
22
import warnings
33
import streamlit.components.v1 as components
4-
from typing import Optional, Union, Callable, Literal
4+
from typing import Optional, Union, Callable, Literal, Dict, Any, List
55

66
from st_link_analysis.component.layouts import LAYOUTS
77
from st_link_analysis.component.styles import NodeStyle, EdgeStyle
@@ -33,17 +33,17 @@ class LinkAnalysisDeprecationWarning(DeprecationWarning):
3333

3434

3535
def st_link_analysis(
36-
elements: dict,
37-
layout: Union[str, dict] = "cose",
38-
node_styles: list[NodeStyle] = [],
39-
edge_styles: list[EdgeStyle] = [],
36+
elements: Dict[str, Any],
37+
layout: Union[str, Dict[str, Any]] = "cose",
38+
node_styles: List[NodeStyle] = [],
39+
edge_styles: List[EdgeStyle] = [],
4040
height: int = 500,
4141
key: Optional[str] = None,
4242
on_change: Optional[Callable[..., None]] = None,
43-
node_actions: list[Literal["remove", "expand"]] = [],
43+
node_actions: List[Literal["remove", "expand"]] = [],
4444
enable_node_actions: Optional[bool] = None, # deprecated
45-
events: list[Event] = [],
46-
) -> None:
45+
events: List[Event] = [],
46+
) -> Any:
4747
"""
4848
Renders a link analysis graph using Cytoscape in Streamlit.
4949
@@ -88,16 +88,18 @@ def st_link_analysis(
8888
app as the component's return value. NOTE: only defined once. Changing the
8989
list of events requires remounting the component.
9090
"""
91-
node_styles = [n.dump() for n in node_styles]
92-
edge_styles = [e.dump() for e in edge_styles]
93-
style = node_styles + edge_styles
91+
node_styles_dump = [n.dump() for n in node_styles]
92+
edge_styles_dump = [e.dump() for e in edge_styles]
93+
style = node_styles_dump + edge_styles_dump
9494

95-
height = str(height) + "px"
95+
height_str = str(height) + "px"
9696

9797
if isinstance(layout, str):
98-
layout = LAYOUTS[layout]
98+
layout_config = LAYOUTS[layout]
99+
else:
100+
layout_config = layout
99101

100-
events = [e.dump() for e in events]
102+
events_dump = [e.dump() for e in events]
101103

102104
# TODO: remove in next version along with imports, docs, and signature
103105
if enable_node_actions is not None:
@@ -112,10 +114,10 @@ def st_link_analysis(
112114
return _component_func(
113115
elements=elements,
114116
style=style,
115-
layout=layout,
116-
height=height,
117+
layout=layout_config,
118+
height=height_str,
117119
key=key,
118120
on_change=on_change,
119121
nodeActions=node_actions,
120-
events=events,
122+
events=events_dump,
121123
)

st_link_analysis/component/events.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""
22
For more details refer to https://js.cytoscape.org/#events
33
"""
4+
from typing import Dict
45

56
RESERVED_NAMES = ["remove", "expand"]
67

@@ -37,7 +38,7 @@ def __init__(
3738
if name in RESERVED_NAMES:
3839
raise ValueError(f"{RESERVED_NAMES} are reserved action names")
3940

40-
def dump(self) -> dict:
41+
def dump(self) -> Dict[str, str]:
4142
return {
4243
"name": self.name,
4344
"event_type": self.event_type,

st_link_analysis/component/styles.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import warnings
2-
3-
from typing import Optional
2+
from typing import Optional, Dict, Any
43

54

65
# TODO: remove if no depreciation warnings
@@ -47,7 +46,7 @@ def __init__(
4746
self.caption = caption
4847
self.icon = icon
4948

50-
def dump(self) -> dict:
49+
def dump(self) -> Dict[str, Any]:
5150
selector = f"node[label='{self.label}']"
5251
style = {}
5352

@@ -124,7 +123,7 @@ def __init__(
124123
if labeled and not caption:
125124
self.caption = "label"
126125

127-
def dump(self) -> dict:
126+
def dump(self) -> Dict[str, Any]:
128127
selector = f"edge[label='{self.label}']"
129128
style = {}
130129

0 commit comments

Comments
 (0)