-
Notifications
You must be signed in to change notification settings - Fork 54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Provide type annotations for the public API #131
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,3 +43,29 @@ jobs: | |
uses: codecov/codecov-action@v3 | ||
with: | ||
token: ${{ secrets.CODECOV_TOKEN }} | ||
|
||
typesafety: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-python@v4 | ||
with: | ||
python-version: '3.12' | ||
cache: 'pip' | ||
|
||
- run: | | ||
python -m venv .venv | ||
source .venv/bin/activate | ||
pip install --upgrade pip | ||
# Tell setuptools to *not* create a PEP 660 import hook and to use | ||
# symlinks instead, so that pyright can still find the package. See | ||
# https://microsoft.github.io/pyright/#/import-resolution?id=editable-installs | ||
pip install --editable . --config-settings editable_mode=strict | ||
|
||
- run: echo "$PWD/.venv/bin" >> $GITHUB_PATH | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What does this do? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This puts the venv on the PATH for all following steps. It lets pyright find the venv as it looks for the current python executable. |
||
|
||
- uses: jakebailey/pyright-action@v1 | ||
with: | ||
ignore-external: true | ||
verify-types: "aocd" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,10 @@ | ||
from __future__ import annotations | ||
|
||
import argparse | ||
import logging | ||
import re | ||
import sys | ||
import typing as t | ||
from dataclasses import dataclass | ||
from datetime import datetime | ||
from itertools import zip_longest | ||
|
@@ -16,7 +19,11 @@ | |
from aocd.utils import get_plugins | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
log: logging.Logger = logging.getLogger(__name__) | ||
Comment on lines
-19
to
+22
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The |
||
|
||
_AnswerElem = t.Literal[ | ||
"a_code", "a_li", "a_pre", "a_em", "b_code", "b_li", "b_pre", "b_em" | ||
] | ||
|
||
|
||
@dataclass | ||
|
@@ -34,17 +41,17 @@ class Page: | |
soup: bs4.BeautifulSoup # The raw_html string parsed into a bs4.BeautifulSoup instance | ||
year: int # AoC puzzle year (2015+) parsed from html title | ||
day: int # AoC puzzle day (1-25) parsed from html title | ||
article_a: bs4.element.Tag # The bs4 tag for the first <article> in the page, i.e. part a | ||
article_b: bs4.element.Tag # The bs4 tag for the second <article> in the page, i.e. part b. It will be `None` if part b locked | ||
article_a: bs4.Tag # The bs4 tag for the first <article> in the page, i.e. part a | ||
article_b: bs4.Tag | None # The bs4 tag for the second <article> in the page, i.e. part b. It will be `None` if part b locked | ||
a_raw: str # The first <article> html as a string | ||
b_raw: str # The second <article> html as a string. Will be `None` if part b locked | ||
b_raw: str | None # The second <article> html as a string. Will be `None` if part b locked | ||
|
||
def __repr__(self): | ||
def __repr__(self) -> str: | ||
part_a_only = "*" if self.article_b is None else "" | ||
return f"<Page({self.year}, {self.day}){part_a_only} at {hex(id(self))}>" | ||
|
||
@classmethod | ||
def from_raw(cls, html): | ||
def from_raw(cls, html: str) -> Page: | ||
soup = _get_soup(html) | ||
title_pat = r"^Day (\d{1,2}) - Advent of Code (\d{4})$" | ||
title_text = soup.title.text | ||
|
@@ -77,7 +84,7 @@ def from_raw(cls, html): | |
) | ||
return page | ||
|
||
def __getattr__(self, name): | ||
def __getattr__(self, name: _AnswerElem) -> t.Sequence[str]: | ||
if not name.startswith(("a_", "b_")): | ||
raise AttributeError(name) | ||
part, sep, tag = name.partition("_") | ||
|
@@ -118,12 +125,12 @@ class Example(NamedTuple): | |
""" | ||
|
||
input_data: str | ||
answer_a: str = None | ||
answer_b: str = None | ||
extra: str = None | ||
answer_a: str | None = None | ||
answer_b: str | None = None | ||
extra: str | None = None | ||
|
||
@property | ||
def answers(self): | ||
def answers(self) -> tuple[str | None, str | None]: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the code-path where these can be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you were thinking of |
||
return self.answer_a, self.answer_b | ||
|
||
|
||
|
@@ -144,7 +151,7 @@ def _get_unique_real_inputs(year, day): | |
return list({}.fromkeys(strs)) | ||
|
||
|
||
def main(): | ||
def main() -> None: | ||
""" | ||
Summarize an example parser's results with historical puzzles' prose, and | ||
compare the performance against a reference implementation | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What Python version is this going to use by default?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point; it should really pick a version. It'll use the value from
.python-version
if that file is present, but if not it'll default to the 'default Python installed on the runner'.