diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 0000000..1f323b2 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,16 @@ +name: Ruff +on: pull_request +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/ruff-action@v3 + with: + args: check --output-format=github + - uses: astral-sh/ruff-action@v3 + with: + args: format --diff \ No newline at end of file diff --git a/api/directus.py b/api/directus.py index 1c9bd4d..0258fcf 100644 --- a/api/directus.py +++ b/api/directus.py @@ -8,7 +8,7 @@ class DirectusAPI: self.base_url = base_url self.access_token = access_token - def __get_raw(self, endpoint, params = None): + def __get_raw(self, endpoint, params=None): if params is None: params = {} for k in params.keys(): @@ -16,16 +16,11 @@ class DirectusAPI: params[k] = json.dumps(params[k]) url = self.base_url + endpoint result = requests.get( - url, - params = params, - headers = { - "Authorization": f"Bearer {self.access_token}", - "Cache-Control": "no-store" - } + url, params=params, headers={"Authorization": f"Bearer {self.access_token}", "Cache-Control": "no-store"} ) return result - def get(self, endpoint, params = None): + def get(self, endpoint, params=None): if params is None: params = {} result = self.__get_raw(endpoint, params) @@ -39,8 +34,8 @@ class DirectusAPI: print(f"Error: {e}") return None return data - - def get_one(self, endpoint, params = None): + + def get_one(self, endpoint, params=None): if params is None: params = {} results = self.get(endpoint, params) @@ -50,12 +45,12 @@ class DirectusAPI: return None else: raise Exception("One result expected, but got more than one result") - - def get_file(self, endpoint, params = None): + + def get_file(self, endpoint, params=None): if params is None: params = {} result = self.__get_raw(endpoint, params) data = result.content if data is None: raise Exception("No data from API") - return data \ No newline at end of file + return data diff --git a/pyproject.toml b/pyproject.toml index c1d7ca4..6e37258 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ select = [ # pycodestyle # Ensure PEP8-compatible code style. "E", + "W", # pep8-naming # Ensure consisten, PEP8-compatible naming. "N", @@ -38,6 +39,11 @@ select = [ "C90", # ruff-specific: No unused noqa directives "RUF100", + ## Write modern python code + # Use f-strings instead of joining strings + "FLY", + # Check refurb rules + "FURB", ] [tool.pytest.ini_options] diff --git a/renderer/comment.py b/renderer/comment.py index 7626af8..9a3251c 100644 --- a/renderer/comment.py +++ b/renderer/comment.py @@ -1,7 +1,6 @@ import re from mistletoe.block_token import BlockToken -from mistletoe.span_token import SpanToken class BlockComment(BlockToken): diff --git a/renderer/fifty_ohm_html_renderer.py b/renderer/fifty_ohm_html_renderer.py index c61e5a9..b53d4e8 100644 --- a/renderer/fifty_ohm_html_renderer.py +++ b/renderer/fifty_ohm_html_renderer.py @@ -172,7 +172,10 @@ class FiftyOhmHtmlRenderer(HtmlRenderer): return f"{lookup[token.first]}{token.second}{lookup[token.third]}" def render_references(self, token): - return f'{self.ref_id}' + return ( + f'{self.ref_id}" + ) def render_question(self, token): return self.question_renderer(token.question_number) diff --git a/renderer/fifty_ohm_latex_renderer.py b/renderer/fifty_ohm_latex_renderer.py index 48ea836..21a9883 100644 --- a/renderer/fifty_ohm_latex_renderer.py +++ b/renderer/fifty_ohm_latex_renderer.py @@ -27,7 +27,7 @@ class FiftyOhmLaTeXRenderer(LaTeXRenderer): Question, Picture, Photo, - Table + Table, ) self.question_renderer = question_renderer @@ -87,7 +87,7 @@ class FiftyOhmLaTeXRenderer(LaTeXRenderer): return rf"\{tagtype}{{{self.render_inner(token)}}}" def render_halfwidth_spaces(self, token): - return f"{token.first}.\,{token.second}." + return rf"{token.first}.\,{token.second}." def render_nonbreaking_spaces(self, token): return f"{token.first}~{token.second}" @@ -105,7 +105,7 @@ class FiftyOhmLaTeXRenderer(LaTeXRenderer): \captionof{{figure}}{{{text}}} \label{{{ref}}}""" - def render_picture(self, token) : + def render_picture(self, token): return self.render_picture_helper(token.id, token.ref, token.text, token.number) @staticmethod @@ -114,26 +114,26 @@ class FiftyOhmLaTeXRenderer(LaTeXRenderer): \captionof{{figure}}{{{text}}} \label{{{ref}}}""" - def render_photo(self, token) : + def render_photo(self, token): return self.render_photo_helper(token.id, token.ref, token.text, token.number) def render_table(self, token): alignments = token.alignment align = "" - for alignment in alignments : + for alignment in alignments: align += alignment table = f"\\begin{{DARCtabular}}{{{align}}}\n" - + for row in token.children: for j, cell in enumerate(row.children): table += self.render_inner(cell) if j < len(row.children) - 1: table += " & " - table += r"\\"+ "\n" + table += r"\\" + "\n" table += "\\end{DARCtabular}" - if token.caption != "" : + if token.caption != "": table += f"\\captionof{{figure}}{{{token.caption}}}\n" table += f"\\label{{{token.name}}}\n" diff --git a/renderer/include.py b/renderer/include.py index 9f2a690..0cf92d3 100644 --- a/renderer/include.py +++ b/renderer/include.py @@ -15,10 +15,10 @@ class Include(BlockToken): @classmethod def read(cls, lines): - re.compile(r'') - line = next(lines) # Consume the line with the include directive + re.compile(r"") + line = next(lines) # Consume the line with the include directive ident = re.match(r"^\s*\[include:\s*([^\]]+)\]", line).group(1) return ident def __init__(self, match): - self.ident = match \ No newline at end of file + self.ident = match diff --git a/renderer/morse.py b/renderer/morse.py index 72eabe6..e47ba86 100644 --- a/renderer/morse.py +++ b/renderer/morse.py @@ -87,4 +87,4 @@ class Morse(SpanToken): return result parse_inner = False - pattern = re.compile(r'\[morse:\s*([^\]]+)\]') + pattern = re.compile(r"\[morse:\s*([^\]]+)\]") diff --git a/renderer/photo.py b/renderer/photo.py index c167887..5634372 100644 --- a/renderer/photo.py +++ b/renderer/photo.py @@ -16,4 +16,4 @@ class Photo(SpanToken): self.id = match_object.group(1) self.ref = match_object.group(2) self.text = match_object.group(3) - self.number = "TODO" \ No newline at end of file + self.number = "TODO" diff --git a/renderer/picture.py b/renderer/picture.py index acfe82c..0477185 100644 --- a/renderer/picture.py +++ b/renderer/picture.py @@ -16,4 +16,4 @@ class Picture(SpanToken): self.id = match_object.group(1) self.ref = match_object.group(2) self.text = match_object.group(3) - self.number = "TODO" \ No newline at end of file + self.number = "TODO" diff --git a/renderer/qso.py b/renderer/qso.py index 6571696..2359ffc 100644 --- a/renderer/qso.py +++ b/renderer/qso.py @@ -25,6 +25,7 @@ class Qso(BlockToken): def __init__(self, match): self.children = match + class QsoLine(BlockToken): @classmethod def parse_line(cls, line): diff --git a/test/test_comment.py b/test/test_comment.py index dedb47f..68118f9 100644 --- a/test/test_comment.py +++ b/test/test_comment.py @@ -24,7 +24,7 @@ def test_comment_latex(): assertions = { "%Comment\nBar": "% Comment\n\nBar\n", "%Comment\n": "% Comment\n", - "Foo 100 % Bar": "\nFoo 100 \% Bar\n", + "Foo 100 % Bar": "\nFoo 100 \\% Bar\n", "Foo\n%Comment\nBar": "\nFoo\n% Comment\n\nBar\n", } diff --git a/test/test_halfwidth_spaces.py b/test/test_halfwidth_spaces.py index 97a57ac..b2e29c7 100644 --- a/test/test_halfwidth_spaces.py +++ b/test/test_halfwidth_spaces.py @@ -17,6 +17,6 @@ def test_halfwidth_space_html(): @pytest.mark.latex def test_halfwidth_space_latex(): input = "Dies ist z.B. ein Test. D.h. hier sollten d.h. Spaces ersetzt worden sein." - target = "\nDies ist z.\,B. ein Test. D.\,h. hier sollten d.\,h. Spaces ersetzt worden sein.\n" + target = "\nDies ist z.\\,B. ein Test. D.\\,h. hier sollten d.\\,h. Spaces ersetzt worden sein.\n" assert mistletoe.markdown(input, FiftyOhmLaTeXRenderer) == target diff --git a/test/test_html.py b/test/test_html.py index 05b8964..714bb34 100644 --- a/test/test_html.py +++ b/test/test_html.py @@ -69,11 +69,13 @@ def question_stub(input): answer_pictures=answer_pictures, ) + def include_stub(include): with open("data/includes.json") as file: includes = json.load(file) return includes.get(include) + def test_html(capsys): with capsys.disabled(): with open("test/acceptanceTest.md") as file: diff --git a/test/test_include.py b/test/test_include.py index 24c02f7..4b024a4 100644 --- a/test/test_include.py +++ b/test/test_include.py @@ -7,7 +7,7 @@ from renderer.fifty_ohm_html_renderer import FiftyOhmHtmlRenderer @pytest.mark.html def test_include_html(): assertions = { - '[include:ident]': "ident\n", + "[include:ident]": "ident\n", } def test_function(input): @@ -15,4 +15,4 @@ def test_include_html(): with FiftyOhmHtmlRenderer(include_handler=test_function) as renderer: for assertion in assertions: - assert renderer.render(Document(assertion)) == assertions[assertion] \ No newline at end of file + assert renderer.render(Document(assertion)) == assertions[assertion] diff --git a/test/test_morse.py b/test/test_morse.py index 9985209..8a80fc2 100644 --- a/test/test_morse.py +++ b/test/test_morse.py @@ -8,12 +8,12 @@ from test.util import paragraph @pytest.mark.html def test_morse_html(): assertions = { - '[morse:a]': FiftyOhmHtmlRenderer.render_morse_helper([[1, 2]]), - '[morse:a] abc [morse:a]': FiftyOhmHtmlRenderer.render_morse_helper([[1, 2]])+ ' abc ' + FiftyOhmHtmlRenderer.render_morse_helper([[1, 2]]), - '[morse: a]': FiftyOhmHtmlRenderer.render_morse_helper([[1, 2]]), - '[morse: aaa]': FiftyOhmHtmlRenderer.render_morse_helper([[1, 2], [1, 2], [1, 2]]), - '[morse: a a]': FiftyOhmHtmlRenderer.render_morse_helper([[1, 2], [3], [1, 2]]), - '[morse: db0]': FiftyOhmHtmlRenderer.render_morse_helper([[2, 1, 1], [2, 1, 1, 1], [2, 2, 2, 2, 2]]), + "[morse:a]": FiftyOhmHtmlRenderer.render_morse_helper([[1, 2]]), + "[morse:a] abc [morse:a]": f"{FiftyOhmHtmlRenderer.render_morse_helper([[1, 2]])} abc {FiftyOhmHtmlRenderer.render_morse_helper([[1, 2]])}", # noqa: E501 + "[morse: a]": FiftyOhmHtmlRenderer.render_morse_helper([[1, 2]]), + "[morse: aaa]": FiftyOhmHtmlRenderer.render_morse_helper([[1, 2], [1, 2], [1, 2]]), + "[morse: a a]": FiftyOhmHtmlRenderer.render_morse_helper([[1, 2], [3], [1, 2]]), + "[morse: db0]": FiftyOhmHtmlRenderer.render_morse_helper([[2, 1, 1], [2, 1, 1, 1], [2, 2, 2, 2, 2]]), } for assertion in assertions: diff --git a/test/test_nonbreaking_spaces.py b/test/test_nonbreaking_spaces.py index 4b52992..68839d8 100644 --- a/test/test_nonbreaking_spaces.py +++ b/test/test_nonbreaking_spaces.py @@ -18,7 +18,7 @@ def test_paragraph_html(): def test_three_points_html(): assertions = { "Heute hatte ich ... zum Mittagessen.": "Heute hatte ich ... zum Mittagessen.", - "Niemals hätte ich gedacht, dass...ich ...nicht kann.": "Niemals hätte ich gedacht, dass...ich ...nicht kann.", + "Niemals hätte ich gedacht, dass...ich ...nicht kann.": "Niemals hätte ich gedacht, dass...ich ...nicht kann.", # noqa: E501 "Oh nein ...ein Pinguin.": "Oh nein ...ein Pinguin.", "Haha .. . Hahaha": "Haha .. . Hahaha", } @@ -55,7 +55,7 @@ def test_paragraph_latex(): def test_three_points_latex(): assertions = { "Heute hatte ich ... zum Mittagessen.": "\nHeute hatte ich~...~zum Mittagessen.\n", - "Niemals hätte ich gedacht, dass...ich ...nicht kann.": "\nNiemals hätte ich gedacht, dass...ich~...nicht kann.\n", + "Niemals hätte ich gedacht, dass...ich ...nicht kann.": "\nNiemals hätte ich gedacht, dass...ich~...nicht kann.\n", # noqa: E501 "Oh nein ...ein Pinguin.": "\nOh nein~...ein Pinguin.\n", "Haha .. . Hahaha": "\nHaha .. . Hahaha\n", } diff --git a/test/test_qso.py b/test/test_qso.py index 231c70c..50bdfa2 100644 --- a/test/test_qso.py +++ b/test/test_qso.py @@ -23,11 +23,11 @@ def test_qso_html(): for assertion in assertions: assert mistletoe.markdown(assertion, FiftyOhmHtmlRenderer) == assertions[assertion] + @pytest.mark.slide def test_qso_slide(): assertions = { - "\nfoo\n> bar\n": - '
\n
foo
\n
bar
\n
\n\n', + "\nfoo\n> bar\n": '
\n
foo
\n
bar
\n
\n\n', # noqa: E501 } for assertion in assertions: diff --git a/test/test_question.py b/test/test_question.py index 526677d..e4e4ceb 100644 --- a/test/test_question.py +++ b/test/test_question.py @@ -24,6 +24,7 @@ def test_question_html(): for assertion in assertions: assert renderer.render(Document(assertion)) == assertions[assertion] + @pytest.mark.html def test_question_translation_html(): assertions = { @@ -34,7 +35,7 @@ def test_question_translation_html(): } def test_function(input): - with open('data/metadata.json') as file: + with open("data/metadata.json") as file: metadata = json.load(file) return metadata[f"{input}"].get("number") @@ -46,14 +47,14 @@ def test_question_translation_html(): @pytest.mark.latex def test_question_latex(): assertions = { - "[question:123]": "\question{123}", - "\n[question:123]\n": "\question{123}", - "\n[question:123]\n[question:123]": "\question{123}\question{123}", - "Foo\n[question:123]\nBar": "\nFoo\n\question{123}\nBar\n", + "[question:123]": r"\question{123}", + "\n[question:123]\n": r"\question{123}", + "\n[question:123]\n[question:123]": r"\question{123}\question{123}", + "Foo\n[question:123]\nBar": "\nFoo\n\\question{123}\nBar\n", } def test_function(input): - return "\\question{"+input+"}" + return "\\question{" + input + "}" with FiftyOhmLaTeXRenderer(test_function) as renderer: for assertion in assertions: diff --git a/test/test_quote.py b/test/test_quote.py index a83f8e8..64ff664 100644 --- a/test/test_quote.py +++ b/test/test_quote.py @@ -24,11 +24,11 @@ def test_quote_html(): @pytest.mark.latex def test_quote_latex(): assertions = { - '"quote"': "\n\enquote{quote}\n", - '" quote "': "\n\enquote{ quote }\n", - '"quote" "': '\n\enquote{quote} "\n', - '"quo te1" filltext "qu ot e2"': "\n\enquote{quo te1} filltext \enquote{qu ot e2}\n", - '"quo *te1*" filltext "qu ot e2"': "\n\enquote{quo \emph{te1}} filltext \enquote{qu ot e2}\n", + '"quote"': "\n\\enquote{quote}\n", + '" quote "': "\n\\enquote{ quote }\n", + '"quote" "': '\n\\enquote{quote} "\n', + '"quo te1" filltext "qu ot e2"': "\n\\enquote{quo te1} filltext \\enquote{qu ot e2}\n", + '"quo *te1*" filltext "qu ot e2"': "\n\\enquote{quo \\emph{te1}} filltext \\enquote{qu ot e2}\n", '""': '\n""\n', } diff --git a/test/test_references.py b/test/test_references.py index 4d60018..ab332b4 100644 --- a/test/test_references.py +++ b/test/test_references.py @@ -10,9 +10,9 @@ def test_references_html(): # Right now this tests only the default values. # The correct behavior can be tested when the information is added to the renderer class assertions = { - "[ref:e_oszilloskop_bildschirmfoto_sinus]": '0', + "[ref:e_oszilloskop_bildschirmfoto_sinus]": '0', # noqa: E501 "[ref:n_rst_r]": '0', - "[ref:Uuuuuh]": '0', # Test the default parameters + "[ref:Uuuuuh]": '0', # Test the default parameters # noqa: E501 } for key, value in assertions.items(): diff --git a/test/test_table.py b/test/test_table.py index 1c507fd..deaba13 100644 --- a/test/test_table.py +++ b/test/test_table.py @@ -11,14 +11,14 @@ def test_table_html(): "| l: a |": '\n\n\n\n
a
\n', "| r: a |": '\n\n\n\n
a
\n', "| c: a |": '\n\n\n\n
a
\n', - "| l: a |\n| b |": '\n\n\n\n\n\n\n
a
b
\n', - "| l: a |\n| b |\n| c |": '\n\n\n\n\n\n\n\n\n\n
a
b
c
\n', - "| a |\n| b |\n| c |": "\n\n\n\n\n\n\n\n\n\n
a
b
c
\n", - "| l: a |\n| *b* |": '\n\n\n\n\n\n\n
a
b
\n', - "| l: a |\n| b |\n[table:n_ab:A und B]": '\n\n\n\n\n\n\n
a
b
A und B
\n', + "| l: a |\n| b |": '\n\n\n\n\n\n\n
a
b
\n', # noqa: E501 + "| l: a |\n| b |\n| c |": '\n\n\n\n\n\n\n\n\n\n
a
b
c
\n', # noqa: E501 + "| a |\n| b |\n| c |": "\n\n\n\n\n\n\n\n\n\n
a
b
c
\n", # noqa: E501 + "| l: a |\n| *b* |": '\n\n\n\n\n\n\n
a
b
\n', # noqa: E501 + "| l: a |\n| b |\n[table:n_ab:A und B]": '\n\n\n\n\n\n\n
a
b
A und B
\n', # noqa: E501 "| l: *a* |": '\n\n\n\n
a
\n', - "| l: a |\n| [morse:a] |": '\n\n\n\n\n\n\n
a
\n\n▄\n\n▄▄▄\n\n
\n', - "| l: abc | r: abc | X: abc |\n| 123 | 456 | 789 | \n | 987 | 654 | 321 | ": '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
abcabcabc
123456789
987654321
\n', + "| l: a |\n| [morse:a] |": '\n\n\n\n\n\n\n
a
\n\n▄\n\n▄▄▄\n\n
\n', # noqa: E501 + "| l: abc | r: abc | X: abc |\n| 123 | 456 | 789 | \n | 987 | 654 | 321 | ": '\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
abcabcabc
123456789
987654321
\n', # noqa: E501 } with FiftyOhmHtmlRenderer() as renderer: diff --git a/test/test_tag.py b/test/test_tag.py index 4af938d..2b2c493 100644 --- a/test/test_tag.py +++ b/test/test_tag.py @@ -76,17 +76,17 @@ def test_thematic_break_latex(): @pytest.mark.latex def test_tag_latex(): assertions = { - "\nFoo\n": "\Margin{\nFoo\n}", - "\nFoo\n": "\MarginDanger{\nFoo\n}", - "\nFoo\n": "\MarginWarning{\nFoo\n}", - "\nFoo\n": "\MarginAttention{\nFoo\n}", - "\nFoo\n": "\MarginTip{\nFoo\n}", - "\nFoo\n": "\WebTip{\nFoo\n}", - "\nFoo\n": "\MarginUnit{\nFoo\n}", - "\nFoo\n": "\MarginInDepth{\nFoo\n}", - "\nFoo\n": "\MarginWebInDepth{\nFoo\n}", - "\nFoo\n": "\WebMargin{\nFoo\n}", - "\nFoo\n": "\FullWidth{\nFoo\n}", + "\nFoo\n": "\\Margin{\nFoo\n}", + "\nFoo\n": "\\MarginDanger{\nFoo\n}", + "\nFoo\n": "\\MarginWarning{\nFoo\n}", + "\nFoo\n": "\\MarginAttention{\nFoo\n}", + "\nFoo\n": "\\MarginTip{\nFoo\n}", + "\nFoo\n": "\\WebTip{\nFoo\n}", + "\nFoo\n": "\\MarginUnit{\nFoo\n}", + "\nFoo\n": "\\MarginInDepth{\nFoo\n}", + "\nFoo\n": "\\MarginWebInDepth{\nFoo\n}", + "\nFoo\n": "\\WebMargin{\nFoo\n}", + "\nFoo\n": "\\FullWidth{\nFoo\n}", "\nFoo\n": "\nFoo\n", "\nFoo\n": "", } @@ -98,9 +98,9 @@ def test_tag_latex(): @pytest.mark.latex def test_thematic_break_and_tag_latex(): assertions = { - "---\n\nFoo\n": "\Margin{\nFoo\n}", - "---\n\nFoo\n\n\nFoo\n": "\Margin{\nFoo\n}\Margin{\nFoo\n}", - "---\n\nFoo\n\n---\n\nFoo\n": "\Margin{\nFoo\n}\Margin{\nFoo\n}", + "---\n\nFoo\n": "\\Margin{\nFoo\n}", + "---\n\nFoo\n\n\nFoo\n": "\\Margin{\nFoo\n}\\Margin{\nFoo\n}", + "---\n\nFoo\n\n---\n\nFoo\n": "\\Margin{\nFoo\n}\\Margin{\nFoo\n}", } for assertion in assertions: diff --git a/test/test_underline.py b/test/test_underline.py index 9edfe16..ec22438 100644 --- a/test/test_underline.py +++ b/test/test_underline.py @@ -23,7 +23,7 @@ def test_underline_latex(): assertions = { "Text": "\n\\underline{Text}\n", " Text Text ": "\n\\underline{ Text Text }\n", - " Text *Text* ": "\n\\underline{ Text \emph{Text} }\n", + " Text *Text* ": "\n\\underline{ Text \\emph{Text} }\n", } for assertion in assertions: