diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cff23e39..682c0032 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,22 +1,17 @@ repos: - - repo: https://github.com/psf/black-pre-commit-mirror - rev: 23.9.1 + - repo: https://github.com/astral-sh/ruff-pre-commit + rev: "v0.12.3" hooks: - - id: black - language_version: python3.12 + - id: ruff-format + - id: ruff-check + args: ["--fix", "--show-fixes"] - repo: https://github.com/nbQA-dev/nbQA - rev: 1.7.0 + rev: 1.9.1 hooks: - - id: nbqa-black - additional_dependencies: [black==23.9.1] - - id: nbqa-pyupgrade - additional_dependencies: [pyupgrade==2.7.3] - - repo: https://github.com/pycqa/flake8 - rev: 6.1.0 - hooks: - - id: flake8 - args: ["--max-line-length=88", "--extend-ignore=E203"] + - id: nbqa-ruff-format + additional_dependencies: [ruff] + - repo: https://github.com/kynan/nbstripout - rev: 0.6.0 + rev: 0.8.1 hooks: - id: nbstripout diff --git a/README.md b/README.md index ab12ca17..cc7a8854 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,9 @@ mamba activate toolbox ## Working with git -We are using `black` and `nbqa-black` as auto-formatters to ensure code quality. -To make sure these tools are running every time you make a commit, set up our +We are using `ruff` as auto-formatter and linter, and `nbqa-ruff-format` as auto-formatter +for notebooks to ensure code quality. To make sure these tools are running every +time you make a commit, set up our ``pre-commit hook`` via ``` $ pre-commit install @@ -71,10 +72,10 @@ reject a commit if any of the checks fail. Any failing checks can then be solved by fixing the issues reported by the `pre-commit hook`. -We use the github workflow in this repository, see . +We use the GitHub workflow in this repository, see . In short, to contribute: 1. Create a new branch and switch to it using `git switch -c ` 1. Make changes and commit 1. Push the Branch using `git push -u origin ` -1. Open a Pull Request on github. +1. Open a Pull Request on GitHub. diff --git a/common/crop.py b/common/crop.py index b34b4954..1de51011 100755 --- a/common/crop.py +++ b/common/crop.py @@ -6,7 +6,7 @@ from shlex import join if len(sys.argv) < 3: - print("Usage: {} in.crop out.pdf".format(sys.argv[0])) + print(f"Usage: {sys.argv[0]} in.crop out.pdf") exit(1) pdfcrop = os.path.dirname(os.path.abspath(__file__)) + "/pdfcrop2.pl" @@ -15,8 +15,9 @@ in_file = sys.argv[1] out_file = sys.argv[2] -s = open(in_file, "r").read() -s = s.splitlines() +with open(in_file) as f: + s = f.read() + s = s.splitlines() source = s[0] page = s[1] @@ -26,7 +27,7 @@ if len(s) > 3: flags = s[3] flags = flags.split() - auto = not "noauto" in flags + auto = "noauto" not in flags cmd0 = ["pdfseparate", "-f", page, "-l", page, source, out_file] print(join(cmd0)) diff --git a/exercises-latex/13-python/loesung.py b/exercises-latex/13-python/loesung.py index 8ea966ad..303623d1 100644 --- a/exercises-latex/13-python/loesung.py +++ b/exercises-latex/13-python/loesung.py @@ -1,13 +1,14 @@ import matplotlib.pyplot as plt import numpy as np import uncertainties.unumpy as unp +from curve_fit import ucurve_fit from uncertainties.unumpy import ( nominal_values as noms, +) +from uncertainties.unumpy import ( std_devs as stds, ) -from curve_fit import ucurve_fit - def make_qty(num, unit, exp="", figures=None): """Format an uncertainties ufloat as a \qty quantity""" @@ -18,7 +19,7 @@ def make_qty(num, unit, exp="", figures=None): else: x = "{0:.{1:}f}".format(num, figures) - return r"\qty{{{}{}}}{{{}}}".format(x, exp, unit) + return rf"\qty{{{x}{exp}}}{{{unit}}}" t, U, U_err = np.genfromtxt("data.txt", unpack=True) @@ -72,7 +73,7 @@ def f(t, a, b, c, d): t \mathbin{/} \unit{\milli\second} & \SetCell[c=2]{c} U \mathbin{/} \unit{\kilo\volt} & & t \mathbin{/} \unit{\milli\second} & \SetCell[c=2]{c} U \mathbin{/} \unit{\kilo\volt} & \\ \midrule -""" +""" # noqa: E501 table_footer = r""" \bottomrule \end{tblr} @@ -84,7 +85,7 @@ def f(t, a, b, c, d): with open("build/loesung-table.tex", "w") as f: f.write(table_header) - for row in zip(t1, U1, t2, U2): + for row in zip(t1, U1, t2, U2, strict=False): f.write(row_template.format(*row)) f.write("\n") f.write(table_footer) diff --git a/exercises-latex/13-python/vorlage.py b/exercises-latex/13-python/vorlage.py index 535b0549..741cc69e 100644 --- a/exercises-latex/13-python/vorlage.py +++ b/exercises-latex/13-python/vorlage.py @@ -1,13 +1,8 @@ -import matplotlib.pyplot as plt import numpy as np -import uncertainties.unumpy as unp from uncertainties.unumpy import ( - nominal_values as noms, std_devs as stds, ) -from curve_fit import ucurve_fit - def make_qty(num, unit, exp="", figures=None): """Format an uncertainties ufloat as a \qty quantity""" @@ -18,4 +13,4 @@ def make_qty(num, unit, exp="", figures=None): else: x = "{0:.{1:}f}".format(num, figures) - return r"\qty{{{}{}}}{{{}}}".format(x, exp, unit) + return rf"\qty{{{x}{exp}}}{{{unit}}}" diff --git a/exercises-toolbox/1-python/5-readwrite/loesung1.py b/exercises-toolbox/1-python/5-readwrite/loesung1.py index ea056618..18ab026d 100644 --- a/exercises-toolbox/1-python/5-readwrite/loesung1.py +++ b/exercises-toolbox/1-python/5-readwrite/loesung1.py @@ -6,6 +6,6 @@ else: filename = "test.txt" -with open(filename, "r") as f: +with open(filename) as f: print(f.read()) # end solution diff --git a/exercises-toolbox/1-python/6-wordcount/loesung3.py b/exercises-toolbox/1-python/6-wordcount/loesung3.py index ed681ea7..dfab7ae9 100644 --- a/exercises-toolbox/1-python/6-wordcount/loesung3.py +++ b/exercises-toolbox/1-python/6-wordcount/loesung3.py @@ -7,5 +7,5 @@ counts = Counter(words) for key, count in counts.most_common(20): - print("{}: {}".format(key, count)) + print(f"{key}: {count}") # end solution diff --git a/exercises-toolbox/1-python/7-fstrings/loesung.py b/exercises-toolbox/1-python/7-fstrings/loesung.py index 8f06169b..ba2441a0 100644 --- a/exercises-toolbox/1-python/7-fstrings/loesung.py +++ b/exercises-toolbox/1-python/7-fstrings/loesung.py @@ -36,7 +36,7 @@ # begin solution print() # Für den Abstand zur letzten Lösung # end solution -for metal, mass in zip(metals, masses): +for metal, mass in zip(metals, masses, strict=False): print() # begin solution print(f"{metal}: {mass}") @@ -51,14 +51,14 @@ # begin solution # Für die 4.Aufgabe: print() # Für den Abstand zur letzten Lösung -for metal, mass in zip(metals, masses): +for metal, mass in zip(metals, masses, strict=False): print(f"{metal}: {mass:0.2f}") # Zum Knobeln für Interessierte: # Wie funktioniert das hier? print() # Für den Abstand zur letzten Lösung -for metal, mass in zip(metals, masses): +for metal, mass in zip(metals, masses, strict=False): offset = 11 - len(metal) print(f"{metal}:", f"{mass:>{offset}.2f}") # end solution diff --git a/exercises-toolbox/2-numpy/1-arrays/loesung.py b/exercises-toolbox/2-numpy/1-arrays/loesung.py index d6821b37..daf6a7f3 100644 --- a/exercises-toolbox/2-numpy/1-arrays/loesung.py +++ b/exercises-toolbox/2-numpy/1-arrays/loesung.py @@ -18,13 +18,13 @@ arrays = [a, b, c, d, e, f, g0, g1, h] print("Aufgabe 1)") -for name, array in zip(array_names, arrays): +for name, array in zip(array_names, arrays, strict=False): print(f"Array {name}: {array}") # Aufgabe 2) print("\nAufgabe 2)") -for name, array in zip(array_names, arrays): +for name, array in zip(array_names, arrays, strict=False): print(f"Array {name}") print(f"\t len({name}): {len(array)}") print(f"\t {name}.shape: {array.shape}") diff --git a/exercises-toolbox/2-numpy/2-indexing/loesung.py b/exercises-toolbox/2-numpy/2-indexing/loesung.py index c0e1bc0f..07a73f1c 100644 --- a/exercises-toolbox/2-numpy/2-indexing/loesung.py +++ b/exercises-toolbox/2-numpy/2-indexing/loesung.py @@ -1,8 +1,7 @@ #! /usr/bin/env python -# encoding: utf-8 -import numpy as np import matplotlib.pyplot as plt +import numpy as np field = np.array( [ diff --git a/exercises-toolbox/2-numpy/5-functions/loesung.py b/exercises-toolbox/2-numpy/5-functions/loesung.py index 7b164d62..cac62f26 100644 --- a/exercises-toolbox/2-numpy/5-functions/loesung.py +++ b/exercises-toolbox/2-numpy/5-functions/loesung.py @@ -1,5 +1,4 @@ #! /usr/bin/env python -# encoding: utf-8 import numpy as np diff --git a/exercises-toolbox/3-matplotlib/6/loesung.py b/exercises-toolbox/3-matplotlib/6/loesung.py index ca564e36..86775575 100644 --- a/exercises-toolbox/3-matplotlib/6/loesung.py +++ b/exercises-toolbox/3-matplotlib/6/loesung.py @@ -1,6 +1,6 @@ # begin solution -import numpy as np import matplotlib.pyplot as plt +import numpy as np x = np.linspace(0, 1, 100) diff --git a/exercises-toolbox/3-matplotlib/7/loesung.py b/exercises-toolbox/3-matplotlib/7/loesung.py index 07d744d6..9f2f5cc7 100644 --- a/exercises-toolbox/3-matplotlib/7/loesung.py +++ b/exercises-toolbox/3-matplotlib/7/loesung.py @@ -1,6 +1,6 @@ # begin solution -import numpy as np import matplotlib.pyplot as plt +import numpy as np x = np.linspace(0, 2 * np.pi, 100) diff --git a/exercises-toolbox/4-scipy/3-polyfit/loesung.py b/exercises-toolbox/4-scipy/3-polyfit/loesung.py index abc04df2..344dd043 100644 --- a/exercises-toolbox/4-scipy/3-polyfit/loesung.py +++ b/exercises-toolbox/4-scipy/3-polyfit/loesung.py @@ -1,6 +1,6 @@ # begin solution -import numpy as np import matplotlib.pyplot as plt +import numpy as np # Generate data rng = np.random.default_rng(210) @@ -21,7 +21,7 @@ def f(x, a, b, c): parameters, covariance_matrix = np.polyfit(x, y, deg=2, cov=True) uncertainties = np.sqrt(np.diag(covariance_matrix)) -for name, value, unc in zip("abc", parameters, uncertainties): +for name, value, unc in zip("abc", parameters, uncertainties, strict=False): print(f"{name} = {value:.3f} ± {unc:.3f}") fig = plt.figure(layout="constrained") diff --git a/exercises-toolbox/4-scipy/4-curve_fit/loesung.py b/exercises-toolbox/4-scipy/4-curve_fit/loesung.py index 22aa49a6..5a3b6586 100644 --- a/exercises-toolbox/4-scipy/4-curve_fit/loesung.py +++ b/exercises-toolbox/4-scipy/4-curve_fit/loesung.py @@ -1,5 +1,5 @@ -import numpy as np import matplotlib.pyplot as plt +import numpy as np from scipy.optimize import curve_fit # begin solution diff --git a/exercises-toolbox/4-scipy/5-peakdetect/loesung.py b/exercises-toolbox/4-scipy/5-peakdetect/loesung.py index 68710aac..e075e871 100644 --- a/exercises-toolbox/4-scipy/5-peakdetect/loesung.py +++ b/exercises-toolbox/4-scipy/5-peakdetect/loesung.py @@ -1,7 +1,7 @@ +import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit from scipy.signal import find_peaks -import matplotlib.pyplot as plt # begin solution diff --git a/exercises-toolbox/4-scipy/6-beugung/loesung.py b/exercises-toolbox/4-scipy/6-beugung/loesung.py index 9d50d2db..694ddeaf 100644 --- a/exercises-toolbox/4-scipy/6-beugung/loesung.py +++ b/exercises-toolbox/4-scipy/6-beugung/loesung.py @@ -1,6 +1,6 @@ +import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit -import matplotlib.pyplot as plt def theory(phi, A0, b): diff --git a/exercises-toolbox/5-uncertainties/1-formel/loesung.py b/exercises-toolbox/5-uncertainties/1-formel/loesung.py index 4db63001..7d803afb 100644 --- a/exercises-toolbox/5-uncertainties/1-formel/loesung.py +++ b/exercises-toolbox/5-uncertainties/1-formel/loesung.py @@ -1,7 +1,7 @@ # begin solution +from sympy import sin, var from uncertainties import ufloat from uncertainties.unumpy import sin as usin -from sympy import var, sin x = ufloat(4.56, 0.2) y = ufloat(2.11, 0.3) diff --git a/exercises-toolbox/5-uncertainties/3-curve_fit/loesung.py b/exercises-toolbox/5-uncertainties/3-curve_fit/loesung.py index d4420104..8deccd04 100644 --- a/exercises-toolbox/5-uncertainties/3-curve_fit/loesung.py +++ b/exercises-toolbox/5-uncertainties/3-curve_fit/loesung.py @@ -39,7 +39,7 @@ def f(x, a, b, c): y = unp.uarray(y_0, y_err) params = ucurve_fit(f, x, y) print("a * cos(x * b) + c") -for char, p in zip("abc", params): +for char, p in zip("abc", params, strict=False): print(f"{char} = {p}") fig = plt.figure(layout="constrained") diff --git a/exercises-toolbox/5-uncertainties/4-linleastsquares/loesung.py b/exercises-toolbox/5-uncertainties/4-linleastsquares/loesung.py index d09ec701..76aedbea 100644 --- a/exercises-toolbox/5-uncertainties/4-linleastsquares/loesung.py +++ b/exercises-toolbox/5-uncertainties/4-linleastsquares/loesung.py @@ -28,7 +28,7 @@ def linleastsquares(functions, x_values, y_values): def linear_combination(x, functions, params): - return np.sum([p * f(x) for p, f in zip(params, functions)], axis=0) + return np.sum([p * f(x) for p, f in zip(params, functions, strict=False)], axis=0) if __name__ == "__main__": diff --git a/exercises-toolbox/7-make/auswertung-bonus-loesung.py b/exercises-toolbox/7-make/auswertung-bonus-loesung.py index 71b0c757..dca25f99 100644 --- a/exercises-toolbox/7-make/auswertung-bonus-loesung.py +++ b/exercises-toolbox/7-make/auswertung-bonus-loesung.py @@ -1,6 +1,6 @@ +import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit -import matplotlib.pyplot as plt def theory(phi, A0, b): diff --git a/exercises-toolbox/7-make/auswertung.py b/exercises-toolbox/7-make/auswertung.py index 53cae41f..0490c1df 100644 --- a/exercises-toolbox/7-make/auswertung.py +++ b/exercises-toolbox/7-make/auswertung.py @@ -1,6 +1,6 @@ +import matplotlib.pyplot as plt import numpy as np from scipy.optimize import curve_fit -import matplotlib.pyplot as plt def theory(phi, A0, b): diff --git a/exercises-toolbox/8-all/303_Der_Lock-In-Verstaerker/loesung.py b/exercises-toolbox/8-all/303_Der_Lock-In-Verstaerker/loesung.py index bd56a79a..9d72787a 100644 --- a/exercises-toolbox/8-all/303_Der_Lock-In-Verstaerker/loesung.py +++ b/exercises-toolbox/8-all/303_Der_Lock-In-Verstaerker/loesung.py @@ -1,9 +1,8 @@ # begin solution -import numpy as np -from uncertainties.unumpy import nominal_values as noms import matplotlib.pyplot as plt - +import numpy as np from curve_fit import ucurve_fit +from uncertainties.unumpy import nominal_values as noms def Ur(r, A, B, C): diff --git a/exercises-toolbox/8-all/354_Gedaempfte_und_erzwungene_Schwingungen/loesung.py b/exercises-toolbox/8-all/354_Gedaempfte_und_erzwungene_Schwingungen/loesung.py index a6f3be21..3774edd5 100644 --- a/exercises-toolbox/8-all/354_Gedaempfte_und_erzwungene_Schwingungen/loesung.py +++ b/exercises-toolbox/8-all/354_Gedaempfte_und_erzwungene_Schwingungen/loesung.py @@ -1,6 +1,6 @@ # begin solution -import numpy as np import matplotlib.pyplot as plt +import numpy as np L, C, R = np.genfromtxt("geraetedaten.txt", unpack=True) L *= 1e-3 diff --git a/exercises-toolbox/8-all/702_Aktivierung_mit_Neutronen/loesung.py b/exercises-toolbox/8-all/702_Aktivierung_mit_Neutronen/loesung.py index f52f3519..748e6aea 100644 --- a/exercises-toolbox/8-all/702_Aktivierung_mit_Neutronen/loesung.py +++ b/exercises-toolbox/8-all/702_Aktivierung_mit_Neutronen/loesung.py @@ -1,11 +1,12 @@ -from linregress import ulinregress +import matplotlib.pyplot as plt # begin solution import numpy as np import uncertainties as unc import uncertainties.unumpy as unp -from uncertainties.unumpy import nominal_values as noms, std_devs as stds -import matplotlib.pyplot as plt +from linregress import ulinregress +from uncertainties.unumpy import nominal_values as noms +from uncertainties.unumpy import std_devs as stds Delta_t_0 = np.genfromtxt("Delta_t_0.txt") N_0 = np.genfromtxt("N_0.txt") diff --git a/exercises-toolbox/8-all/corona/loesung.py b/exercises-toolbox/8-all/corona/loesung.py index 2100e53b..b618062f 100644 --- a/exercises-toolbox/8-all/corona/loesung.py +++ b/exercises-toolbox/8-all/corona/loesung.py @@ -1,5 +1,5 @@ -import numpy as np import matplotlib.pyplot as plt +import numpy as np data = np.genfromtxt( "./FB53-Coronafallzahlen.csv", diff --git a/exercises-toolbox/8-all/example-report/generate-step-files.py b/exercises-toolbox/8-all/example-report/generate-step-files.py index 72fbedf1..967b7123 100644 --- a/exercises-toolbox/8-all/example-report/generate-step-files.py +++ b/exercises-toolbox/8-all/example-report/generate-step-files.py @@ -2,77 +2,119 @@ import re import sys from collections import defaultdict -from dataclasses import dataclass from collections.abc import Iterable +from dataclasses import dataclass STEPRANGEREGEX = re.compile(r"(?:#|%)\s*<(\d*)(-(\d*)|)>") -@dataclass + +@dataclass class Templateline: linenumber: int line: str output_file_indices: Iterable pattern: str - + def __str__(self): pattern_length = len(self.pattern) - indicies = f"{self.output_file_indices[0]},...,{self.output_file_indices[-1]}" - # magic number 10: the amount of padding necessary to print a pattern with two two-digit numbers - return f"({self.pattern} → [{indicies}]) {" "*(10-pattern_length)} {self.linenumber:>3} {self.line}" + indicies = f"{self.output_file_indices[0]},...,{self.output_file_indices[-1]}" + # magic number 10: the amount of padding necessary to print + # a pattern with two two-digit numbers + return f"({self.pattern} → [{indicies}]) {' ' * (10 - pattern_length)} {self.linenumber:>3} {self.line}" # noqa: E501 def setup_arg_parser(): parser = argparse.ArgumentParser( - prog="generate-step-files", - description="Generate multiple (step)files containing lines from a template file", - epilog='') - - parser.add_argument('-v', '--verbose', action='store_true', - help="Get info on parsed args, the step maximum steprange in the template and to be removed lines.") - parser.add_argument('-n', '--dry-run', action='store_true', - help="Print the content of each output file to stdout instead of generating any files.") + prog="generate-step-files", + description="""Generate multiple (step)files containing + lines from a template file""", + epilog="", + ) + + parser.add_argument( + "-v", + "--verbose", + action="store_true", + help="""Get info on parsed args, the step maximum steprange + in the template and to be removed lines.""", + ) + parser.add_argument( + "-n", + "--dry-run", + action="store_true", + help="""Print the content of each output file to stdout + instead of generating any files.""", + ) # This option allows to use the same step numbering in differnt independent files - parser.add_argument('-s', '--start-step', type=int, default=1, - help="Set the step that should be considered step 1 for this file") - parser.add_argument('-t','--template_filepath', dest='template_filepath', required=True, - help="Filepath to the template file.") - parser.add_argument('-o', '--output_filepaths', dest='output_filepaths', action="append", required=True, - help="Filepaths to the output files (you need to use one Option -o for each file). Hint: use -o=file{1,2,3} for example, to generate the multiple options.)") - return parser + parser.add_argument( + "-s", + "--start-step", + type=int, + default=1, + help="Set the step that should be considered step 1 for this file", + ) + parser.add_argument( + "-t", + "--template_filepath", + dest="template_filepath", + required=True, + help="Filepath to the template file.", + ) + parser.add_argument( + "-o", + "--output_filepaths", + dest="output_filepaths", + action="append", + required=True, + help="""Filepaths to the output files (you need to use one Option -o + for each file). Hint: use -o=file{1,2,3} for example, to generate the + multiple options.)""", + ) + return parser + def parse_lines_and_stepranges(lines, start_step, end_step): template_lines = [] removed_lines = [] - for i,l in enumerate(lines, start=1): + for i, l in enumerate(lines, start=1): found = STEPRANGEREGEX.search(l) - - # a line containing no pattern will not be saved to any output file, hence 'removed' - if found is None: - removed_lines.append(Templateline(i,l, [], "")) + + # a line containing no pattern will not be saved to + # any output file, hence 'removed' + if found is None: + removed_lines.append(Templateline(i, l, [], "")) continue groups = found.groups() - - try: + + try: lower_step_limit = int(groups[0]) except ValueError: - raise ValueError(f"The pattern ({found.group()}) in line {i} of the template file has not starting step.") - + raise ValueError( + f"The pattern ({found.group()}) in line {i} of the template " + "file has not starting step." + ) from None + # Since the end_step is calculated from the number of output files given # the lower index has to be changed to be less then the upper index lower_index = lower_step_limit - start_step if lower_index < 0: - raise ValueError(f"The given star_step {start_step} is higher then the lower limit in the pattern '{found.group()}' in line {i} of the template file.") - + raise ValueError( + f"The given star_step {start_step} is higher then the lower limit " + "in the pattern '{found.group()}' in line {i} of the template file." + ) from None + # The dash and second number can be omitted: # e.g. <4> is equivalent to <4-4> if (not groups[1]) and (groups[2] is None): # To include anything the upper index has to be increased by 1 step_limits = (lower_index, lower_index + 1) - # If the second number is omitted but the dash is not, the upper limit is the last step: + # If the second number is omitted but the dash is not, the upper limit + # is the last step: # e.g. <4-> is equivalent to <4-10> if 10 output files are generated elif not groups[2]: - # the number of files given is used for the upper index (it is already 1 greater then the highest possible index) + # the number of files given is used for the upper index (it is already + # 1 greater then the highest possible index) upper_index = end_step step_limits = (lower_index, upper_index) @@ -81,22 +123,27 @@ def parse_lines_and_stepranges(lines, start_step, end_step): upper_step_limit = int(groups[2]) upper_index = upper_step_limit - start_step + 1 - step_limits = (lower_index, upper_index) + step_limits = (lower_index, upper_index) - num_files_with_current_line = (step_limits[1] - step_limits[0]) + num_files_with_current_line = step_limits[1] - step_limits[0] if num_files_with_current_line > end_step: - raise ValueError(f"The number of given output files is {end_step}," - f" but line {i} of the template file is expected to appear in {num_files_with_current_line} output files (pattern: {found.group()}).") - - # remove the steprange pattern and spaces between line content and pattern - line_content = STEPRANGEREGEX.sub("", l).rstrip() - template_lines.append(Templateline(i, line_content, list(range(*step_limits)), found.group())) + raise ValueError( + f"The number of given output files is {end_step}," + f" but line {i} of the template file is expected to " + f"appear in {num_files_with_current_line} output files " + f"(pattern: {found.group()})." + ) from None + + # remove the steprange pattern and spaces between line content and pattern + line_content = STEPRANGEREGEX.sub("", l).rstrip() + template_lines.append( + Templateline(i, line_content, list(range(*step_limits)), found.group()) + ) return template_lines, removed_lines def split_stepfile_lines(template_lines, output_filepaths): - lines_per_stepfile = defaultdict(list) for line in template_lines: for step in line.output_file_indices: @@ -111,21 +158,21 @@ def main(): template_filepath = args.template_filepath output_filepaths = args.output_filepaths - if args.verbose: print("Input:") - print(' '.join(sys.argv)) + print(" ".join(sys.argv)) print("Parsed:") print(f" - template file: {template_filepath}") print(f" - output files: {output_filepaths}") print(f" - start step: {args.start_step}") - with open(template_filepath) as fh: template_lines = fh.readlines() - template_lines, removed_lines = parse_lines_and_stepranges(template_lines, args.start_step, len(output_filepaths)) + template_lines, removed_lines = parse_lines_and_stepranges( + template_lines, args.start_step, len(output_filepaths) + ) lines_per_stepfiles = split_stepfile_lines(template_lines, output_filepaths) @@ -133,19 +180,22 @@ def main(): print("Removed lines:") print(f"{'\n'.join(str(rl) for rl in removed_lines)}") print(f"Found steps: {lines_per_stepfiles.keys()}") - if args.dry_run: for stepfile, lines in lines_per_stepfiles.items(): - print(f"\nOutput file '{stepfile}' with index ({output_filepaths.index(stepfile)}) would contain these lines from the template file:") - print(f"pattern → indicies{" "*9}ln line") - print(f"{"\n".join(str(l) for l in lines)}") - return - + print( + f"\nOutput file '{stepfile}' with index " + f"({output_filepaths.index(stepfile)}) " + "would contain these lines from the template file:" + ) + print(f"pattern → indicies{' ' * 9}ln line") + print(f"{'\n'.join(str(l) for l in lines)}") + return for stepfile, lines in lines_per_stepfiles.items(): with open(stepfile, "w") as fh: fh.write("\n".join(l.line for l in lines).strip()) + if __name__ == "__main__": main() diff --git a/exercises-toolbox/8-all/example-report/templates/latex_formatting.py b/exercises-toolbox/8-all/example-report/templates/latex_formatting.py index 61069449..b2b294c1 100644 --- a/exercises-toolbox/8-all/example-report/templates/latex_formatting.py +++ b/exercises-toolbox/8-all/example-report/templates/latex_formatting.py @@ -3,6 +3,7 @@ std_devs as stds, ) + def make_qty(num, unit, exp="", figures=None, formatting=None): """Format an uncertainties ufloat as a \qty quantity""" if np.any(stds([num])): @@ -11,13 +12,9 @@ def make_qty(num, unit, exp="", figures=None, formatting=None): x = f"{num:.{figures:}uf}".replace("/", "") else: x = f"{num:.{figures:}f}" - if exp and not str(exp).startswith('e'): - exp = 'e' + str(exp) + if exp and not str(exp).startswith("e"): + exp = "e" + str(exp) if formatting: return rf"\qty[{formatting}]{{{x}{exp}}}{{{unit}}}" return rf"\qty{{{x}{exp}}}{{{unit}}}" - - - - diff --git a/intro/script/answers.py b/intro/script/answers.py index 7f51da6b..80034ce8 100644 --- a/intro/script/answers.py +++ b/intro/script/answers.py @@ -1,7 +1,8 @@ -import pandas as pd -import matplotlib.pyplot as plt import json +import matplotlib.pyplot as plt +import pandas as pd + plt.style.use("ggplot") plt.rcParams["font.family"] = "sans-serif" @@ -136,7 +137,7 @@ def interests(answers): if __name__ == "__main__": - with open("data/toolbox2024.json", "r") as read_file: + with open("data/toolbox2024.json") as read_file: data = json.load(read_file) study(data) operating_system(data) diff --git a/intro/script/download.py b/intro/script/download.py index c24f65a9..949cb72f 100644 --- a/intro/script/download.py +++ b/intro/script/download.py @@ -1,7 +1,8 @@ -from getpass import getpass import json -import requests +from getpass import getpass + import pandas as pd +import requests r = requests.get( "https://registration.pep-dortmund.org/events/21/participants", diff --git a/intro/script/example_plot.py b/intro/script/example_plot.py index a37b6856..cdb25fa0 100644 --- a/intro/script/example_plot.py +++ b/intro/script/example_plot.py @@ -1,5 +1,5 @@ -import numpy as np import matplotlib.pyplot as plt +import numpy as np from scipy.optimize import curve_fit PROPERTIES = { diff --git a/latex/script/answers.py b/latex/script/answers.py index dfbb65b2..87316593 100644 --- a/latex/script/answers.py +++ b/latex/script/answers.py @@ -1,11 +1,12 @@ -import pandas as pd -import matplotlib.pyplot as plt import json +import matplotlib.pyplot as plt +import pandas as pd + plt.style.use("ggplot") plt.rcParams["font.family"] = "sans-serif" -with open("../intro/data/toolbox2024.json", "r") as read_file: +with open("../intro/data/toolbox2024.json") as read_file: answers = json.load(read_file) liste = [] diff --git a/latex/script/mattex1.py b/latex/script/mattex1.py index 6d9ec935..08c568d8 100644 --- a/latex/script/mattex1.py +++ b/latex/script/mattex1.py @@ -1,15 +1,6 @@ - - import matplotlib.pyplot as plt import numpy as np - - - - - - - x = np.linspace(0, 10, 1000) y = x ** np.sin(x) diff --git a/latex/script/mattex2.py b/latex/script/mattex2.py index 788647f1..b332333a 100644 --- a/latex/script/mattex2.py +++ b/latex/script/mattex2.py @@ -1,15 +1,6 @@ - - import matplotlib.pyplot as plt import numpy as np - - - - - - - x = np.linspace(0, 10, 1000) y = x ** np.sin(x) # set figure size and use constrained_layout diff --git a/latex/script/mattex3.py b/latex/script/mattex3.py index ceb7b821..3a2b8548 100644 --- a/latex/script/mattex3.py +++ b/latex/script/mattex3.py @@ -1,8 +1,10 @@ import matplotlib as mpl -mpl.use("pgf") # <-- Use LaTeX Backend + +mpl.use("pgf") # <-- Use LaTeX Backend import matplotlib.pyplot as plt import numpy as np -mpl.rcParams.update( # <-- Set matplotlib options + +mpl.rcParams.update( # <-- Set matplotlib options { "font.family": "serif", "text.usetex": True, diff --git a/latex/script/mattex4.py b/latex/script/mattex4.py index 790060a5..85dd55cd 100644 --- a/latex/script/mattex4.py +++ b/latex/script/mattex4.py @@ -1,7 +1,9 @@ import matplotlib as mpl + mpl.use("pgf") import matplotlib.pyplot as plt import numpy as np + mpl.rcParams.update( { "font.family": "serif", diff --git a/latex/script/mattex5.py b/latex/script/mattex5.py index d3cd4de7..07e6a71a 100644 --- a/latex/script/mattex5.py +++ b/latex/script/mattex5.py @@ -1,13 +1,6 @@ import matplotlib.pyplot as plt import numpy as np - - - - - - - x = np.linspace(0, 10, 1000) y = x ** np.sin(x) diff --git a/make/make-example/plot1.py b/make/make-example/plot1.py index 7bbea41f..293b411e 100644 --- a/make/make-example/plot1.py +++ b/make/make-example/plot1.py @@ -1,5 +1,5 @@ -import numpy as np import matplotlib.pyplot as plt +import numpy as np data = np.genfromtxt("data.txt", unpack=True) diff --git a/make/make-example/plot2.py b/make/make-example/plot2.py index cfa38f72..4b01d93c 100644 --- a/make/make-example/plot2.py +++ b/make/make-example/plot2.py @@ -1,5 +1,5 @@ -import numpy as np import matplotlib.pyplot as plt +import numpy as np data = np.genfromtxt("data.txt", unpack=True) data2 = np.genfromtxt("data2.txt", unpack=True) diff --git a/pygments_style/setup.py b/pygments_style/setup.py index accd7ce0..a930947f 100644 --- a/pygments_style/setup.py +++ b/pygments_style/setup.py @@ -1,13 +1,8 @@ from setuptools import setup - setup( name="toobox_style", version="1.0.0", py_modules=["toolbox_style"], - entry_points={ - "pygments.styles": [ - "toolbox = toolbox_style:Toolbox" - ] - } + entry_points={"pygments.styles": ["toolbox = toolbox_style:Toolbox"]}, ) diff --git a/python/matplotlib.ipynb b/python/matplotlib.ipynb index bef99c0d..172109bb 100644 --- a/python/matplotlib.ipynb +++ b/python/matplotlib.ipynb @@ -221,7 +221,6 @@ "cell_type": "code", "execution_count": null, "metadata": { - "scrolled": true, "tags": [] }, "outputs": [], diff --git a/python/muon_plot.py b/python/muon_plot.py index 39f25b7e..3d1293c2 100644 --- a/python/muon_plot.py +++ b/python/muon_plot.py @@ -1,9 +1,9 @@ import matplotlib.pyplot as plt import numpy as np +import uncertainties.unumpy as unp +from matplotlib.patches import Rectangle from scipy.optimize import curve_fit from uncertainties import correlated_values -from matplotlib.patches import Rectangle -import uncertainties.unumpy as unp nom = unp.nominal_values std = unp.std_devs diff --git a/python/numeric-python.ipynb b/python/numeric-python.ipynb index bae81be9..4bb46633 100644 --- a/python/numeric-python.ipynb +++ b/python/numeric-python.ipynb @@ -170,6 +170,7 @@ "outputs": [], "source": [ "import math\n", + "\n", "# This doesn't work\n", "math.cos(x_arr)" ] diff --git a/python/scientific-python.ipynb b/python/scientific-python.ipynb index 767eb280..271a4e03 100644 --- a/python/scientific-python.ipynb +++ b/python/scientific-python.ipynb @@ -188,7 +188,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "jupyter": { "outputs_hidden": true } diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 00000000..5abd3718 --- /dev/null +++ b/ruff.toml @@ -0,0 +1,28 @@ +target-version = "py313" +line-length = 88 +extend-exclude = ["python/*.ipynb"] # let nbqa handle notebooks + +[lint] +select = [ + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # isort + "I", +] +ignore = ["E203", "E741"] + +fixable = ["ALL"] +unfixable = [] + +[format] +quote-style = "double" +indent-style = "space" +line-ending = "auto" +skip-magic-trailing-comma = false +docstring-code-format = true