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