Skip to content

Commit 5d721e1

Browse files
authored
chore: add types (#225)
* chore: add mypy testing Scaffolding in the testing, and will not complete succssfully yet. Will be followed by code changes to pass. Signed-off-by: Mike Fiedler <[email protected]> * lint: ignore empty dict Surfaced via `mypy`, in that an empty dict could not infer what types could be there. Instead of importing `typing` and annotating the empty Dict, I opted to ignore the line, as we do not expect to populate the dict at all, and are using it to **prevent** additions to the value. Signed-off-by: Mike Fiedler <[email protected]> * chore: remove unused styles parameter Surfaced via `mypy`, recommended adding a type to the empty list. The list was originally empty back in 0.1.0. Instead of adding a type, remove the constant, and the code that uses it from `clean()` - as it was partially reverted in #121. The default `ALLOWED_STYLES` in the underlying library is `[]`. Related: #114 (comment) Signed-off-by: Mike Fiedler <[email protected]> * fix: correct import for unescape Surfaced via `mypy`, in that the `html.parser` module does not have a direct implementation of `unescape`. Refs: https://docs.python.org/3.6/library/html.html#html.unescape In #192 support for Python 2.7 was removed, the import path changed. This works due to imports placing the imported code in the local scope. If the `html.parser` module ever stopped importing `unescape`, this import would break as a result. Signed-off-by: Mike Fiedler <[email protected]> * chore: update pytest markers cli flag Currently emits a warning: PytestRemovedIn8Warning: The --strict option is deprecated, use --strict-markers instead. Signed-off-by: Mike Fiedler <[email protected]> * chore(types): add types to clean module Surfaced by running mypy in strict mode, and added types where relevant. Signed-off-by: Mike Fiedler <[email protected]> * chore(types): add types to txt module Signed-off-by: Mike Fiedler <[email protected]> * chore(types): add types to markdown module Signed-off-by: Mike Fiedler <[email protected]> * chore: add types to rst module The types-docutils hints are still incomplete, good progress is being made. See: python/typeshed#7256 I've had to use an ignore on the class inheritance, and a couple of `typing.Any` annotations until that package implements more type hints. Signed-off-by: Mike Fiedler <[email protected]> * chore: ignore distutils module from types `mypy` strict mode is having a hard time with the `distutils` imports, since they are wrapped in `setuptools` right now as a private package. This pacakge's distutils integration will need to be reworked anyhow. Left a comment with details at the top of the file. Signed-off-by: Mike Fiedler <[email protected]> * test: use strict mode for mypy Prevent new things from creeping in during development. Signed-off-by: Mike Fiedler <[email protected]> * chore: tell the world we've got types Include a blank `py.typed` file in the package to inform `mypy` that there's types to be found in this package. Signed-off-by: Mike Fiedler <[email protected]> * chore: move strict flag to config Allows other tools to ebenfit from a consistent configuration. Signed-off-by: Mike Fiedler <[email protected]> * refactor: change imports to be consistent with others Signed-off-by: Mike Fiedler <[email protected]> * docs: add inline details for specific ignores Signed-off-by: Mike Fiedler <[email protected]> * lint: apply more specific type Signed-off-by: Mike Fiedler <[email protected]> * docs: add comment to why source is Any Signed-off-by: Mike Fiedler <[email protected]> * lint: replace typing imports with relative ones Signed-off-by: Mike Fiedler <[email protected]>
1 parent 5ad13fd commit 5d721e1

File tree

10 files changed

+72
-23
lines changed

10 files changed

+72
-23
lines changed

.github/workflows/ci.yml

+2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ jobs:
3232
run: python -m pip install tox
3333
- name: Run linting
3434
run: python -m tox -e pep8
35+
- name: Run mypy
36+
run: python -m tox -e mypy
3537
packaging:
3638
name: Packaging
3739
runs-on: ubuntu-latest

MANIFEST.in

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
include LICENSE README.rst CHANGES.rst
22
include tox.ini .coveragerc pytest.ini
3+
include readme_renderer/py.typed
34

45
recursive-include tests *.html
56
recursive-include tests *.py

pyproject.toml

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,13 @@
11
[build-system]
22
requires = ["setuptools>=40.8.0", "wheel", "bleach>=2.1.0", "docutils>=0.13.1", "Pygments>=2.5.1"]
33
build-backend = "setuptools.build_meta:__legacy__"
4+
5+
[tool.mypy]
6+
strict = true
7+
warn_unused_configs = true
8+
[[tool.mypy.overrides]]
9+
# These modules do not yet have types available.
10+
module = [
11+
"cmarkgfm.*"
12+
]
13+
ignore_missing_imports = true

readme_renderer/clean.py

+11-10
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from __future__ import absolute_import, division, print_function
1515

1616
import functools
17+
from typing import Any, Dict, Iterator, List, Optional
1718

1819
import bleach
1920
import bleach.callbacks
@@ -59,15 +60,14 @@
5960
"input": ["type", "checked", "disabled"],
6061
}
6162

62-
ALLOWED_STYLES = [
63-
]
64-
6563

6664
class DisabledCheckboxInputsFilter:
67-
def __init__(self, source):
65+
# The typeshed for bleach (html5lib) filters is incomplete, use `typing.Any`
66+
# See https://github.com/python/typeshed/blob/505ea726415016e53638c8b584b8fdc9c722cac1/stubs/bleach/bleach/html5lib_shim.pyi#L7-L8 # noqa E501
67+
def __init__(self, source: Any) -> None:
6868
self.source = source
6969

70-
def __iter__(self):
70+
def __iter__(self) -> Iterator[Dict[str, Optional[str]]]:
7171
for token in self.source:
7272
if token.get("name") == "input":
7373
# only allow disabled checkbox inputs
@@ -85,23 +85,24 @@ def __iter__(self):
8585
else:
8686
yield token
8787

88-
def __getattr__(self, name):
88+
def __getattr__(self, name: str) -> Any:
8989
return getattr(self.source, name)
9090

9191

92-
def clean(html, tags=None, attributes=None, styles=None):
92+
def clean(
93+
html: str,
94+
tags: Optional[List[str]] = None,
95+
attributes: Optional[Dict[str, List[str]]] = None
96+
) -> Optional[str]:
9397
if tags is None:
9498
tags = ALLOWED_TAGS
9599
if attributes is None:
96100
attributes = ALLOWED_ATTRIBUTES
97-
if styles is None:
98-
styles = ALLOWED_STYLES
99101

100102
# Clean the output using Bleach
101103
cleaner = bleach.sanitizer.Cleaner(
102104
tags=tags,
103105
attributes=attributes,
104-
styles=styles,
105106
filters=[
106107
# Bleach Linkify makes it easy to modify links, however, we will
107108
# not be using it to create additional links.

readme_renderer/integration/distutils.py

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14+
15+
# The `distutils` integration is going to need to get updated to `setuptools``
16+
# soon enough, as `distutils` is deprecated and will be removed in Python 3.12.
17+
# There's currently some pass-through imports that allow this to work, but is
18+
# challenging for `mypy` in `strict` mode, so let's skip this file for now.
19+
# See https://peps.python.org/pep-0632/
20+
# mypy: ignore-errors
1421
from __future__ import absolute_import, division, print_function
1522

1623
import cgi

readme_renderer/markdown.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515

1616
import re
1717
import warnings
18+
from typing import Any, Match, Optional
1819

19-
from html.parser import unescape
20+
from html import unescape
2021

2122
import pygments
2223
import pygments.lexers
@@ -51,7 +52,11 @@
5152
}
5253

5354

54-
def render(raw, variant="GFM", **kwargs):
55+
def render(
56+
raw: str,
57+
variant: str = "GFM",
58+
**kwargs: Any
59+
) -> Optional[str]:
5560
if not variants:
5661
warnings.warn(_EXTRA_WARNING)
5762
return None
@@ -61,7 +66,8 @@ def render(raw, variant="GFM", **kwargs):
6166
if not renderer:
6267
return None
6368

64-
rendered = renderer(raw)
69+
# The renderer is a lambda function, and mypy fails lambdas right now.
70+
rendered = renderer(raw) # type: ignore
6571

6672
if not rendered:
6773
return None
@@ -71,7 +77,7 @@ def render(raw, variant="GFM", **kwargs):
7177
return cleaned
7278

7379

74-
def _highlight(html):
80+
def _highlight(html: str) -> str:
7581
"""Syntax-highlights HTML-rendered Markdown.
7682
7783
Plucks sections to highlight that conform the the GitHub fenced code info
@@ -94,7 +100,7 @@ def _highlight(html):
94100
'(?(in_code)|<code>)(?P<code>.+?)'
95101
r'</code></pre>', re.DOTALL)
96102

97-
def replacer(match):
103+
def replacer(match: Match[Any]) -> str:
98104
try:
99105
lang = match.group('lang')
100106
lang = _LANG_ALIASES.get(lang, lang)

readme_renderer/py.typed

Whitespace-only changes.

readme_renderer/rst.py

+17-5
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,28 @@
1414
from __future__ import absolute_import, division, print_function
1515

1616
import io
17+
from typing import Any, Dict, IO, Optional, Union
1718

1819
from docutils.core import publish_parts
20+
from docutils.nodes import colspec, image
1921
from docutils.writers.html4css1 import HTMLTranslator, Writer
2022
from docutils.utils import SystemMessage
2123

2224
from .clean import clean
2325

2426

25-
class ReadMeHTMLTranslator(HTMLTranslator):
27+
class ReadMeHTMLTranslator(HTMLTranslator): # type: ignore[misc] # docutils is incomplete, returns `Any` python/typeshed#7256 # noqa E501
2628

2729
# Overrides base class not to output `<object>` tag for SVG images.
28-
object_image_types = {}
29-
30-
def emptytag(self, node, tagname, suffix="\n", **attributes):
30+
object_image_types: Dict[str, str] = {}
31+
32+
def emptytag(
33+
self,
34+
node: Union[colspec, image],
35+
tagname: str,
36+
suffix: str = "\n",
37+
**attributes: Any
38+
) -> Any:
3139
"""Override this to add back the width/height attributes."""
3240
if tagname == "img":
3341
if "width" in node:
@@ -95,7 +103,11 @@ def emptytag(self, node, tagname, suffix="\n", **attributes):
95103
}
96104

97105

98-
def render(raw, stream=None, **kwargs):
106+
def render(
107+
raw: str,
108+
stream: Optional[IO[str]] = None,
109+
**kwargs: Any
110+
) -> Optional[str]:
99111
if stream is None:
100112
# Use a io.StringIO as the warning stream to prevent warnings from
101113
# being printed to sys.stderr.

readme_renderer/txt.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from __future__ import absolute_import, division, print_function
1515

1616
import sys
17+
from typing import Any, Optional
1718

1819
from .clean import clean
1920

@@ -26,6 +27,6 @@ def html_escape(s):
2627
return escape(s, quote=True).replace("'", '&#x27;')
2728

2829

29-
def render(raw, **kwargs):
30+
def render(raw: str, **kwargs: Any) -> Optional[str]:
3031
rendered = html_escape(raw).replace("\n", "<br>")
3132
return clean(rendered, tags=["br"])

tox.ini

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
[tox]
2-
envlist = py36,py37,py38,py39,py310,pep8,packaging,noextra
2+
envlist = py36,py37,py38,py39,py310,pep8,packaging,noextra,mypy
33

44
[testenv]
55
deps =
66
pytest
77
commands =
8-
pytest --strict {posargs}
8+
pytest --strict-markers {posargs}
99
extras = md
1010

11+
[testenv:mypy]
12+
basepython = python3
13+
deps =
14+
mypy
15+
types-bleach
16+
types-docutils
17+
types-Pygments
18+
commands = mypy readme_renderer
19+
1120
[testenv:pep8]
1221
basepython = python3
1322
deps =

0 commit comments

Comments
 (0)