Skip to content

Commit fd77aaf

Browse files
committed
more types
1 parent 96c4a30 commit fd77aaf

3 files changed

Lines changed: 211 additions & 13 deletions

File tree

.gitignore

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
share/python-wheels/
24+
*.egg-info/
25+
.installed.cfg
26+
*.egg
27+
MANIFEST
28+
29+
# PyInstaller
30+
# Usually these files are written by a python script from a template
31+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
32+
*.manifest
33+
*.spec
34+
35+
# Installer logs
36+
pip-log.txt
37+
pip-delete-this-directory.txt
38+
39+
# Unit test / coverage reports
40+
htmlcov/
41+
.tox/
42+
.nox/
43+
.coverage
44+
.coverage.*
45+
.cache
46+
nosetests.xml
47+
coverage.xml
48+
*.cover
49+
*.py,cover
50+
.hypothesis/
51+
.pytest_cache/
52+
cover/
53+
54+
# Translations
55+
*.mo
56+
*.pot
57+
58+
# Django stuff:
59+
*.log
60+
local_settings.py
61+
db.sqlite3
62+
db.sqlite3-journal
63+
64+
# Flask stuff:
65+
instance/
66+
.webassets-cache
67+
68+
# Scrapy stuff:
69+
.scrapy
70+
71+
# Sphinx documentation
72+
docs/_build/
73+
74+
# PyBuilder
75+
.pybuilder/
76+
target/
77+
78+
# Jupyter Notebook
79+
.ipynb_checkpoints
80+
81+
# IPython
82+
profile_default/
83+
ipython_config.py
84+
85+
# pyenv
86+
# For a library or package, you might want to ignore these files since the code is
87+
# intended to run in multiple environments; otherwise, check them in:
88+
# .python-version
89+
90+
# pipenv
91+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
93+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
94+
# install all needed dependencies.
95+
#Pipfile.lock
96+
97+
# UV
98+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99+
# This is especially recommended for binary packages to ensure reproducibility, and is more
100+
# commonly ignored for libraries.
101+
#uv.lock
102+
103+
# poetry
104+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105+
# This is especially recommended for binary packages to ensure reproducibility, and is more
106+
# commonly ignored for libraries.
107+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108+
#poetry.lock
109+
110+
# pdm
111+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
112+
#pdm.lock
113+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
114+
# in version control.
115+
# https://pdm.fming.dev/latest/usage/project/#working-with-version-control
116+
.pdm.toml
117+
.pdm-python
118+
.pdm-build/
119+
120+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
121+
__pypackages__/
122+
123+
# Celery stuff
124+
celerybeat-schedule
125+
celerybeat.pid
126+
127+
# SageMath parsed files
128+
*.sage.py
129+
130+
# Environments
131+
.env
132+
.venv
133+
env/
134+
venv/
135+
ENV/
136+
env.bak/
137+
venv.bak/
138+
139+
# Spyder project settings
140+
.spyderproject
141+
.spyproject
142+
143+
# Rope project settings
144+
.ropeproject
145+
146+
# mkdocs documentation
147+
/site
148+
149+
# mypy
150+
.mypy_cache/
151+
.dmypy.json
152+
dmypy.json
153+
154+
# Pyre type checker
155+
.pyre/
156+
157+
# pytype static type analyzer
158+
.pytype/
159+
160+
# Cython debug symbols
161+
cython_debug/
162+
163+
# PyCharm
164+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
165+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
166+
# and can be added to the global gitignore or merged into this file. For a more nuclear
167+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
168+
#.idea/
169+
170+
# Visual Studio Code
171+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
172+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
173+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
174+
# you could uncomment the following to ignore the enitre vscode folder
175+
# .vscode/
176+
177+
# Ruff stuff:
178+
.ruff_cache/
179+
180+
# PyPI configuration file
181+
.pypirc
182+
183+
# Cursor
184+
# Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
185+
# exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
186+
# refer to https://docs.cursor.com/context/ignore-files
187+
.cursorignore
188+
.cursorindexingignore

src/htmlcmp/compare_output.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Config:
1717
thread_local = threading.local()
1818

1919

20-
def parse_json(path: Path):
20+
def parse_json(path: Path) -> dict:
2121
if not isinstance(path, Path):
2222
raise TypeError(f"Expected Path, got {type(path)}")
2323
if not path.is_file():
@@ -27,7 +27,7 @@ def parse_json(path: Path):
2727
return json.load(f)
2828

2929

30-
def compare_json(a: Path, b: Path):
30+
def compare_json(a: Path, b: Path) -> bool:
3131
if not isinstance(a, Path) or not isinstance(b, Path):
3232
raise TypeError("Both arguments must be of type Path")
3333
if not a.is_file() or not b.is_file():
@@ -38,7 +38,7 @@ def compare_json(a: Path, b: Path):
3838
return json_a == json_b
3939

4040

41-
def compare_html(a: Path, b: Path, browser=None, diff_output: Path = None):
41+
def compare_html(a: Path, b: Path, browser=None, diff_output: Path = None) -> bool:
4242
if not isinstance(a, Path) or not isinstance(b, Path):
4343
raise TypeError("Both arguments must be of type Path")
4444
if not a.is_file() or not b.is_file():
@@ -56,7 +56,7 @@ def compare_html(a: Path, b: Path, browser=None, diff_output: Path = None):
5656
return result
5757

5858

59-
def compare_files(a: Path, b: Path, **kwargs):
59+
def compare_files(a: Path, b: Path, **kwargs) -> bool:
6060
if not isinstance(a, Path) or not isinstance(b, Path):
6161
raise TypeError("Both arguments must be of type Path")
6262
if not a.is_file() or not b.is_file():
@@ -70,7 +70,7 @@ def compare_files(a: Path, b: Path, **kwargs):
7070
return compare_html(a, b, **kwargs)
7171

7272

73-
def comparable_file(path: Path):
73+
def comparable_file(path: Path) -> bool:
7474
if not isinstance(path, Path):
7575
raise TypeError(f"Expected Path, got {type(path)}")
7676
if not path.is_file():
@@ -83,7 +83,9 @@ def comparable_file(path: Path):
8383
return False
8484

8585

86-
def submit_compare_dirs(a: Path, b: Path, executor, diff_output: Path = None, **kwargs):
86+
def submit_compare_dirs(
87+
a: Path, b: Path, executor, diff_output: Path = None, **kwargs
88+
) -> dict[str, list[Path]]:
8789
if not isinstance(a, Path) or not isinstance(b, Path):
8890
raise TypeError("Both arguments must be of type Path")
8991
if not a.is_dir() or not b.is_dir():
@@ -155,7 +157,7 @@ def compare(path_a, path_b, diff_output):
155157

156158
def print_results(
157159
results: dict[str, list[Path]], a: Path, b: Path, level: int = 0, prefix: str = ""
158-
):
160+
) -> dict[str, list[Path]]:
159161
if not isinstance(a, Path) or not isinstance(b, Path):
160162
raise TypeError("Both arguments must be of type Path")
161163
if not a.is_dir() or not b.is_dir():

src/htmlcmp/html_render_diff.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from selenium.webdriver.support.ui import WebDriverWait
1515

1616

17-
def to_url(path: str | Path):
17+
def to_url(path: str | Path) -> str:
1818
if not isinstance(path, (str, Path)):
1919
raise TypeError(f"Expected str or Path, got {type(path)}")
2020

@@ -25,9 +25,11 @@ def to_url(path: str | Path):
2525
return path
2626

2727

28-
def screenshot(browser, url: str):
28+
def screenshot(browser: webdriver.Remote, url: str) -> Image.Image:
2929
if not isinstance(url, str):
3030
raise TypeError(f"Expected str, got {type(url)}")
31+
if not isinstance(browser, webdriver.Remote):
32+
raise TypeError(f"Expected webdriver.Remote, got {type(browser)}")
3133

3234
browser.get(url)
3335

@@ -57,7 +59,9 @@ def screenshot(browser, url: str):
5759
return Image.open(io.BytesIO(png))
5860

5961

60-
def get_browser(driver: str, max_width: int = 1000, max_height: int = 10000):
62+
def get_browser(
63+
driver: str, max_width: int = 1000, max_height: int = 10000
64+
) -> webdriver.Remote:
6165
if not isinstance(driver, str):
6266
raise TypeError(f"Expected str, got {type(driver)}")
6367
if not isinstance(max_width, int) or not isinstance(max_height, int):
@@ -81,9 +85,13 @@ def get_browser(driver: str, max_width: int = 1000, max_height: int = 10000):
8185
return browser
8286

8387

84-
def html_render_diff(a: str | Path, b: str | Path, browser):
85-
if browser is None:
86-
raise TypeError("Browser instance cannot be None")
88+
def html_render_diff(
89+
a: str | Path, b: str | Path, browser: webdriver.Remote
90+
) -> tuple[Image.Image, tuple[Image.Image, Image.Image]]:
91+
if not isinstance(a, (str, Path)) or not isinstance(b, (str, Path)):
92+
raise TypeError("Both a and b must be str or Path instances")
93+
if not isinstance(browser, webdriver.Remote):
94+
raise TypeError(f"Expected webdriver.Remote, got {type(browser)}")
8795

8896
image_a = screenshot(browser, to_url(a))
8997
image_b = screenshot(browser, to_url(b))

0 commit comments

Comments
 (0)