diff --git a/.flake8 b/.flake8 deleted file mode 100644 index cb2ed23..0000000 --- a/.flake8 +++ /dev/null @@ -1,10 +0,0 @@ -[flake8] -exclude = - .eggs, - build, -extend-ignore = - # math, https://github.com/PyCQA/pycodestyle/issues/513 - W503, -per-file-ignores = - # ignore unused imports - __init__.py: F401 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 2f8baef..1f5613e 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -14,10 +14,10 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up Python 3.8 + - name: Set up Python 3.10 uses: actions/setup-python@v4 with: - python-version: '3.8' + python-version: '3.10' - name: Install pre-commit hooks run: | diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 92a17ee..119cb13 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,13 +9,15 @@ # # default_language_version: - python: python3.8 + python: python3.10 repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.0.276 + rev: v0.1.8 hooks: - id: ruff + args: [ --fix ] + - id: ruff-format - repo: https://github.com/codespell-project/codespell rev: v2.2.4 hooks: diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index d910255..5f33f4f 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -41,7 +41,7 @@ Coding Convention ----------------- We follow the PEP8_ convention for Python code -and check for correct syntax with ruff_. +and use ruff_ as a linter and code formatter. In addition, we check for common spelling errors with codespell_. Both tools and possible exceptions @@ -61,13 +61,14 @@ You can also install ruff_ and codespell_ and call it directly:: pip install ruff codespell # consider system wide installation - ruff check . + ruff check --fix . # lint all Python files, and fix any fixable errors + ruff format . # format code of all Python files codespell It can be restricted to specific folders:: - ruff check audfoo/ tests/ - codespell audfoo/ tests/ + ruff check audplot/ tests/ + codespell audplot/ tests/ .. _codespell: https://github.com/codespell-project/codespell/ diff --git a/audplot/__init__.py b/audplot/__init__.py index c0ac3c2..4f8abcd 100644 --- a/audplot/__init__.py +++ b/audplot/__init__.py @@ -17,6 +17,7 @@ # Dynamically get the version of the installed module try: import importlib.metadata + __version__ = importlib.metadata.version(__name__) except Exception: # pragma: no cover importlib = None # pragma: no cover diff --git a/audplot/core/api.py b/audplot/core/api.py index 18625e6..eadacb9 100644 --- a/audplot/core/api.py +++ b/audplot/core/api.py @@ -19,12 +19,12 @@ def cepstrum( - cc_matrix: np.ndarray, - hop_duration: float, - *, - channel: int = 0, - ax: matplotlib.axes._axes.Axes = None, - cmap: str = 'magma', + cc_matrix: np.ndarray, + hop_duration: float, + *, + channel: int = 0, + ax: matplotlib.axes._axes.Axes = None, + cmap: str = "magma", ) -> matplotlib.image.AxesImage: r"""Cepstrum. @@ -51,7 +51,7 @@ def cepstrum( >>> import librosa >>> import matplotlib.pyplot as plt - >>> x, sr = librosa.load(librosa.ex('trumpet')) + >>> x, sr = librosa.load(librosa.ex("trumpet")) >>> y = librosa.feature.mfcc(y=x, sr=sr) >>> hop_dur = 512 / sr # default hop length is 512 >>> image = cepstrum(y, hop_dur) @@ -65,16 +65,16 @@ def cepstrum( n_cc, n_cepstra = cc_matrix.shape extent = [0, n_cepstra * hop_duration, -0.5, n_cc - 0.5] - ax.set_ylabel('Cepstral Coefficients') - ax.set_xlabel('Time / s') + ax.set_ylabel("Cepstral Coefficients") + ax.set_xlabel("Time / s") ax.margins(x=0) image = ax.imshow( cc_matrix, - aspect='auto', - origin='lower', + aspect="auto", + origin="lower", cmap=cmap, - interpolation='none', + interpolation="none", extent=extent, ) @@ -91,14 +91,14 @@ def cepstrum( def confusion_matrix( - truth: typing.Union[typing.Sequence, pd.Series], - prediction: typing.Union[typing.Sequence, pd.Series], - *, - labels: typing.Sequence = None, - label_aliases: typing.Dict = None, - percentage: bool = False, - show_both: bool = False, - ax: matplotlib.axes.Axes = None, + truth: typing.Union[typing.Sequence, pd.Series], + prediction: typing.Union[typing.Sequence, pd.Series], + *, + labels: typing.Sequence = None, + label_aliases: typing.Dict = None, + percentage: bool = False, + show_both: bool = False, + ax: matplotlib.axes.Axes = None, ): r"""Confusion matrix between ground truth and prediction. @@ -158,9 +158,9 @@ def confusion_matrix( .. plot:: :context: close-figs - >>> confusion_matrix(truth, prediction, label_aliases={0: 'A', 1: 'B', 2: 'C'}) + >>> confusion_matrix(truth, prediction, label_aliases={0: "A", 1: "B", 2: "C"}) - """ # noqa: 501 + """ # noqa: E501 ax = ax or plt.gca() if labels is None: labels = audmetric.utils.infer_labels(truth, prediction) @@ -175,7 +175,7 @@ def confusion_matrix( # Set format of first row labels in confusion matrix if percentage: - annot = cm.applymap(lambda x: f'{100 * x:.0f}%') + annot = cm.applymap(lambda x: f"{100 * x:.0f}%") else: annot = cm.applymap(lambda x: human_format(x)) @@ -191,24 +191,21 @@ def confusion_matrix( if percentage: annot2 = cm2.applymap(lambda x: human_format(x)) else: - annot2 = cm2.applymap(lambda x: f'{100 * x:.0f}%') + annot2 = cm2.applymap(lambda x: f"{100 * x:.0f}%") # Combine strings from two dataframes # by vectorizing the underlying function. # See: https://stackoverflow.com/a/42277839 def combine_string(x, y): - return f'{x}\n({y})' + return f"{x}\n({y})" combine_string = np.vectorize(combine_string) annot = pd.DataFrame(combine_string(annot, annot2), index=labels) # Get label names to present on x- and y-axis if label_aliases is not None: - labels = [ - label_aliases.get(label, label) - for label in labels - ] + labels = [label_aliases.get(label, label) for label in labels] sns.heatmap( cm, @@ -216,24 +213,24 @@ def combine_string(x, y): xticklabels=labels, yticklabels=labels, cbar=False, - fmt='', - cmap='Blues', + fmt="", + cmap="Blues", ax=ax, ) - ax.tick_params(axis='y', rotation=0) - ax.set_xlabel('Prediction') - ax.set_ylabel('Truth') + ax.tick_params(axis="y", rotation=0) + ax.set_xlabel("Prediction") + ax.set_ylabel("Truth") def detection_error_tradeoff( - x: typing.Union[typing.Sequence, pd.Series], - y: typing.Union[typing.Sequence, pd.Series], - *, - error_rates: bool = False, - xlim: typing.Sequence = [0.001, 0.5], - ylim: typing.Sequence = [0.001, 0.5], - label: str = None, - ax: matplotlib.axes.Axes = None, + x: typing.Union[typing.Sequence, pd.Series], + y: typing.Union[typing.Sequence, pd.Series], + *, + error_rates: bool = False, + xlim: typing.Sequence = [0.001, 0.5], + ylim: typing.Sequence = [0.001, 0.5], + label: str = None, + ax: matplotlib.axes.Axes = None, ) -> typing.Callable: r"""Detection error tradeoff curve. @@ -298,7 +295,9 @@ def detection_error_tradeoff( >>> # Random prediction >>> pred1 = np.random.random_sample(2000) >>> # Better than random prediction - >>> pred2 = np.zeros(2000,) + >>> pred2 = np.zeros( + ... 2000, + ... ) >>> pred2[:1000] = np.random.normal(loc=0.6, scale=0.1, size=1000) >>> pred2[1000:] = np.random.normal(loc=0.4, scale=0.1, size=1000) >>> pred2 = np.clip(pred2, 0, 1) @@ -307,12 +306,12 @@ def detection_error_tradeoff( ... pred1, ... xlim=[0.01, 0.99], # use large limits for random ... ylim=[0.01, 0.99], - ... label='pred1', + ... label="pred1", ... ) >>> # Add pred2 to plot using transformed FMR and FNMR values >>> import audmetric >>> fmr, fnmr, _ = audmetric.detection_error_tradeoff(truth, pred2) - >>> _ = plt.plot(transform(fmr), transform(fnmr), label='pred2') + >>> _ = plt.plot(transform(fmr), transform(fnmr), label="pred2") >>> _ = plt.legend() >>> plt.tight_layout() @@ -330,17 +329,14 @@ def detection_error_tradeoff( y=transform(y), label=label, ) - ax.set_title('Detection Error Tradeoff (DET) Curve') - ax.set_xlabel('False Match Rate') - ax.set_ylabel('False Non-Match Rate') + ax.set_title("Detection Error Tradeoff (DET) Curve") + ax.set_xlabel("False Match Rate") + ax.set_ylabel("False Non-Match Rate") ax.grid(alpha=0.4) ticks = [0.001, 0.01, 0.05, 0.2, 0.4, 0.6, 0.8, 0.95, 0.99] tick_locations = transform(ticks) - tick_labels = [ - f'{t:.0%}' if (100 * t).is_integer() else f'{t:.1%}' - for t in ticks - ] + tick_labels = [f"{t:.0%}" if (100 * t).is_integer() else f"{t:.1%}" for t in ticks] g.set(xticks=tick_locations, xticklabels=tick_labels) g.set(yticks=tick_locations, yticklabels=tick_labels) ax.set_xlim(transform(xlim[0]), transform(xlim[1])) @@ -352,10 +348,10 @@ def detection_error_tradeoff( def distribution( - truth: typing.Union[typing.Sequence, pd.Series], - prediction: typing.Union[typing.Sequence, pd.Series], - *, - ax: matplotlib.axes.Axes = None, + truth: typing.Union[typing.Sequence, pd.Series], + prediction: typing.Union[typing.Sequence, pd.Series], + *, + ax: matplotlib.axes.Axes = None, ): r"""Distribution of truth and predicted values. @@ -385,15 +381,15 @@ def distribution( ax = ax or plt.gca() data = pd.DataFrame( data=np.array([truth, prediction]).T, - columns=['Truth', 'Prediction'], + columns=["Truth", "Prediction"], ) sns.histplot( data, common_bins=False, - stat='frequency', + stat="frequency", kde=True, edgecolor=None, - kde_kws={'cut': 3}, # hard code like in distplot() + kde_kws={"cut": 3}, # hard code like in distplot() ax=ax, ) ax.grid(alpha=0.4) @@ -403,7 +399,7 @@ def distribution( def human_format( - number: typing.Union[int, float], + number: typing.Union[int, float], ) -> str: r"""Display large or small numbers in a human readable way. @@ -457,48 +453,48 @@ def human_format( '-1k' """ - sign = '' + sign = "" if number == 0: - return '0' + return "0" if number < 0: - sign = '-' + sign = "-" number = -1 * number units = [ - 'n', # 10^-9 nano - 'u', # 10^-6 micro - 'm', # 10^-3 milli - '', # 0 - 'k', # 10^3 thousand - 'M', # 10^6 Million Mega - 'B', # 10^9 Billion Giga - 'T', # 10^12 Trillion Tera - 'P', # 10^15 Quadrillion Peta - 'E', # 10^18 Quintillion Exa - 'Z', # 10^21 Sextillion Zetta - 'Y', # 10^24 Septillion Yotta + "n", # 10^-9 nano + "u", # 10^-6 micro + "m", # 10^-3 milli + "", # 0 + "k", # 10^3 thousand + "M", # 10^6 Million Mega + "B", # 10^9 Billion Giga + "T", # 10^12 Trillion Tera + "P", # 10^15 Quadrillion Peta + "E", # 10^18 Quintillion Exa + "Z", # 10^21 Sextillion Zetta + "Y", # 10^24 Septillion Yotta ] k = 1000.0 magnitude = int(math.floor(math.log(number, k))) - number = f'{number / k**magnitude:.1f}' + number = f"{number / k**magnitude:.1f}" if magnitude >= 9: - raise ValueError('Only magnitudes < 1000 ** 9 are supported.') + raise ValueError("Only magnitudes < 1000 ** 9 are supported.") if magnitude <= -4: - raise ValueError('Only magnitudes > 1000 ** -4 are supported.') + raise ValueError("Only magnitudes > 1000 ** -4 are supported.") # Make sure we show only up to 3 significant digits if len(number) > 4: number = number[:-2] - if number.endswith('.0'): + if number.endswith(".0"): number = number[:-2] - return f'{sign}{number}{units[magnitude + 3]}' + return f"{sign}{number}{units[magnitude + 3]}" def scatter( - truth: typing.Union[typing.Sequence, pd.Series], - prediction: typing.Union[typing.Sequence, pd.Series], - *, - fit: bool = False, - order: int = 1, - ax: matplotlib.axes.Axes = None, + truth: typing.Union[typing.Sequence, pd.Series], + prediction: typing.Union[typing.Sequence, pd.Series], + *, + fit: bool = False, + order: int = 1, + ax: matplotlib.axes.Axes = None, ): r"""Scatter plot of truth and predicted values. @@ -532,22 +528,22 @@ def scatter( x=truth, y=prediction, fit_reg=fit, - line_kws={'color': 'r'}, + line_kws={"color": "r"}, order=order, ax=ax, seed=0, ) - ax.set_xlabel('Truth') - ax.set_ylabel('Prediction') + ax.set_xlabel("Truth") + ax.set_ylabel("Prediction") ax.grid(alpha=0.4) sns.despine(ax=ax) def series( - truth: typing.Union[typing.Sequence, pd.Series], - prediction: typing.Union[typing.Sequence, pd.Series], - *, - ax: matplotlib.axes.Axes = None, + truth: typing.Union[typing.Sequence, pd.Series], + prediction: typing.Union[typing.Sequence, pd.Series], + *, + ax: matplotlib.axes.Axes = None, ): r"""Time series plot of truth and predicted values. @@ -578,17 +574,17 @@ def series( ax.plot(truth) ax.plot(prediction) ax.set_ylim(minimum, maximum) - ax.legend(['Truth', 'Prediction']) + ax.legend(["Truth", "Prediction"]) ax.grid(alpha=0.4) sns.despine(ax=ax) def signal( - x: np.ndarray, - sampling_rate: float, - *, - channel: int = 0, - ax: plt.Axes = None, + x: np.ndarray, + sampling_rate: float, + *, + channel: int = 0, + ax: plt.Axes = None, ): r"""Time signal. @@ -610,7 +606,7 @@ def signal( :context: close-figs >>> import librosa - >>> x, sr = librosa.load(librosa.ex('trumpet')) + >>> x, sr = librosa.load(librosa.ex("trumpet")) >>> signal(x, sr) """ @@ -618,7 +614,7 @@ def signal( x = x[channel] if x.ndim == 2 else x time = np.arange(len(x)) / sampling_rate - ax.set_xlabel('Time / s') + ax.set_xlabel("Time / s") ax.margins(x=0) ax.plot(time, x) @@ -627,13 +623,13 @@ def signal( def spectrum( - magnitude: np.ndarray, - hop_duration: float, - centers: np.ndarray, - *, - channel: int = 0, - cmap: str = 'magma', - ax: matplotlib.axes.Axes = None, + magnitude: np.ndarray, + hop_duration: float, + centers: np.ndarray, + *, + channel: int = 0, + cmap: str = "magma", + ax: matplotlib.axes.Axes = None, ) -> matplotlib.image.AxesImage: r"""Plot spectrum. @@ -662,13 +658,13 @@ def spectrum( >>> import librosa >>> import matplotlib.pyplot as plt - >>> x, sr = librosa.load(librosa.ex('trumpet')) + >>> x, sr = librosa.load(librosa.ex("trumpet")) >>> y = librosa.feature.melspectrogram(y=x, sr=sr, n_mels=40, fmax=4000) >>> y_db = librosa.power_to_db(y, ref=np.max) >>> hop_dur = 512 / sr # default hop length is 512 >>> centers = librosa.mel_frequencies(n_mels=40, fmax=4000) >>> image = spectrum(y_db, hop_dur, centers) - >>> cb = plt.colorbar(image, format='%+2.0f dB') + >>> cb = plt.colorbar(image, format="%+2.0f dB") >>> cb.outline.set_visible(False) >>> plt.tight_layout() @@ -678,16 +674,16 @@ def spectrum( frequencies, times = magnitude.shape extent = [0, times * hop_duration, -0.5, frequencies - 0.5] - ax.set_ylabel('Frequency / Hz') - ax.set_xlabel('Time / s') + ax.set_ylabel("Frequency / Hz") + ax.set_xlabel("Time / s") ax.margins(x=0) image = ax.imshow( magnitude, - aspect='auto', - origin='lower', + aspect="auto", + origin="lower", cmap=cmap, - interpolation='none', + interpolation="none", extent=extent, ) @@ -709,14 +705,14 @@ def spectrum( def waveform( - x: np.ndarray, - *, - text: str = None, - color: typing.Union[str, typing.Sequence[float]] = '#E13B41', - background: typing.Union[str, typing.Sequence[float]] = '#FFFFFF00', - linewidth: float = 1.5, - ylim: typing.Sequence[float] = (-1, 1), - ax: matplotlib.axes.Axes = None, + x: np.ndarray, + *, + text: str = None, + color: typing.Union[str, typing.Sequence[float]] = "#E13B41", + background: typing.Union[str, typing.Sequence[float]] = "#FFFFFF00", + linewidth: float = 1.5, + ylim: typing.Sequence[float] = (-1, 1), + ax: matplotlib.axes.Axes = None, ): r"""Plot waveform of a mono signal. @@ -748,38 +744,38 @@ def waveform( :context: close-figs >>> import librosa - >>> x, _ = librosa.load(librosa.ex('trumpet')) - >>> waveform(x, text='Trumpet') + >>> x, _ = librosa.load(librosa.ex("trumpet")) + >>> waveform(x, text="Trumpet") .. plot:: :context: close-figs >>> import librosa - >>> x, _ = librosa.load(librosa.ex('trumpet')) - >>> waveform(x, background='#363636', color='#f6f6f6') + >>> x, _ = librosa.load(librosa.ex("trumpet")) + >>> waveform(x, background="#363636", color="#f6f6f6") .. plot:: :context: close-figs >>> import librosa >>> import matplotlib.pyplot as plt - >>> x, _ = librosa.load(librosa.ex('trumpet', hq=True), mono=False) + >>> x, _ = librosa.load(librosa.ex("trumpet", hq=True), mono=False) >>> _, axs = plt.subplots(2, figsize=(8, 3)) >>> plt.subplots_adjust(hspace=0) >>> waveform( ... x[0, :], - ... text='Left ', # empty space for same size as 'Right' + ... text="Left ", # empty space for same size as 'Right' ... linewidth=0.5, - ... background='#389DCD', - ... color='#1B5975', + ... background="#389DCD", + ... color="#1B5975", ... ax=axs[0], ... ) >>> waveform( ... x[1, :], - ... text='Right', + ... text="Right", ... linewidth=0.5, - ... background='#CA5144', - ... color='#742A23', + ... background="#CA5144", + ... color="#742A23", ... ax=axs[1], ... ) @@ -789,8 +785,8 @@ def waveform( # If axis/figure exist already it will have no effect # Set default figsize if no existing figure is used - default_figsize = plt.rcParams['figure.figsize'] - plt.rcParams['figure.figsize'] = (8, 1) + default_figsize = plt.rcParams["figure.figsize"] + plt.rcParams["figure.figsize"] = (8, 1) fig = plt.gcf() ax = ax or plt.gca() @@ -798,7 +794,7 @@ def waveform( x = np.atleast_2d(x) channels, samples = x.shape if channels > 1: - raise RuntimeError('Only mono signals are supported.') + raise RuntimeError("Only mono signals are supported.") x = x[0] # Set colors @@ -849,11 +845,11 @@ def waveform( -space_around_text, 0, text, - fontsize='large', - fontweight='semibold', + fontsize="large", + fontweight="semibold", color=color, - horizontalalignment='right', - verticalalignment='center', + horizontalalignment="right", + verticalalignment="center", ) # Get left position of text and adjust xlim accordingly fig = ax.get_figure() @@ -866,4 +862,4 @@ def waveform( ax.set(xlim=xlim) # Restore default figure size - plt.rcParams['figure.figsize'] = default_figsize + plt.rcParams["figure.figsize"] = default_figsize diff --git a/docs/conf.py b/docs/conf.py index 08c3fb8..f30c751 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -7,70 +7,70 @@ import audeer -config = toml.load(audeer.path('..', 'pyproject.toml')) +config = toml.load(audeer.path("..", "pyproject.toml")) # Project ----------------------------------------------------------------- -author = ', '.join(author['name'] for author in config['project']['authors']) -copyright = f'2020-{date.today().year} audEERING GmbH' -project = config['project']['name'] +author = ", ".join(author["name"] for author in config["project"]["authors"]) +copyright = f"2020-{date.today().year} audEERING GmbH" +project = config["project"]["name"] version = audeer.git_repo_version() -title = 'Documentation' +title = "Documentation" # General ----------------------------------------------------------------- -master_doc = 'index' -source_suffix = '.rst' +master_doc = "index" +source_suffix = ".rst" exclude_patterns = [ - 'api-src', - 'build', - 'tests', - 'Thumbs.db', - '.DS_Store', + "api-src", + "build", + "tests", + "Thumbs.db", + ".DS_Store", ] -templates_path = ['_templates'] +templates_path = ["_templates"] pygments_style = None extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.napoleon', # support for Google-style docstrings - 'sphinx.ext.autosummary', - 'sphinx.ext.viewcode', - 'sphinx.ext.intersphinx', - 'sphinx_autodoc_typehints', - 'sphinx_copybutton', # for "copy to clipboard" buttons - 'sphinxcontrib.katex', # has to be before jupyter_sphinx - 'matplotlib.sphinxext.plot_directive', # include resulting figures in doc + "sphinx.ext.autodoc", + "sphinx.ext.napoleon", # support for Google-style docstrings + "sphinx.ext.autosummary", + "sphinx.ext.viewcode", + "sphinx.ext.intersphinx", + "sphinx_autodoc_typehints", + "sphinx_copybutton", # for "copy to clipboard" buttons + "sphinxcontrib.katex", # has to be before jupyter_sphinx + "matplotlib.sphinxext.plot_directive", # include resulting figures in doc ] # Do not copy prompot output -copybutton_prompt_text = r'>>> |\.\.\. ' +copybutton_prompt_text = r">>> |\.\.\. " copybutton_prompt_is_regexp = True # Mapping to external documentation intersphinx_mapping = { - 'audmath': ('https://audeering.github.io/audmath/', None), - 'audmetric': ('https://audeering.github.io/audmetric/', None), - 'matplotlib': ('https://matplotlib.org/stable/', None), - 'numpy': ('https://docs.scipy.org/doc/numpy/', None), - 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), - 'python': ('https://docs.python.org/3/', None), - 'scipy': ('https://docs.scipy.org/doc/scipy/', None), + "audmath": ("https://audeering.github.io/audmath/", None), + "audmetric": ("https://audeering.github.io/audmetric/", None), + "matplotlib": ("https://matplotlib.org/stable/", None), + "numpy": ("https://docs.scipy.org/doc/numpy/", None), + "pandas": ("https://pandas.pydata.org/pandas-docs/stable/", None), + "python": ("https://docs.python.org/3/", None), + "scipy": ("https://docs.scipy.org/doc/scipy/", None), } # Disable Gitlab as we need to sign in linkcheck_ignore = [ - 'https://gitlab.audeering.com', + "https://gitlab.audeering.com", ] # Plotting plot_include_source = True plot_html_show_source_link = False plot_html_show_formats = False -plot_pre_code = '' +plot_pre_code = "" plot_rcparams = { - 'figure.figsize': '5, 3.8', # inch + "figure.figsize": "5, 3.8", # inch } -plot_formats = ['svg'] +plot_formats = ["svg"] # Disable auto-generation of TOC entries in the API # https://github.com/sphinx-doc/sphinx/issues/6316 @@ -78,25 +78,24 @@ # HTML -------------------------------------------------------------------- -html_theme = 'sphinx_audeering_theme' +html_theme = "sphinx_audeering_theme" html_theme_options = { - 'display_version': True, - 'logo_only': False, - 'footer_links': False, + "display_version": True, + "logo_only": False, + "footer_links": False, } html_context = { - 'display_github': True, + "display_github": True, } html_title = title # Copy API (sub-)module RST files to docs/api/ folder --------------------- -audeer.rmdir('api') -audeer.mkdir('api') -api_src_files = audeer.list_file_names('api-src') +audeer.rmdir("api") +audeer.mkdir("api") +api_src_files = audeer.list_file_names("api-src") api_dst_files = [ - audeer.path('api', os.path.basename(src_file)) - for src_file in api_src_files + audeer.path("api", os.path.basename(src_file)) for src_file in api_src_files ] for src_file, dst_file in zip(api_src_files, api_dst_files): shutil.copyfile(src_file, dst_file) diff --git a/docs/usage.rst b/docs/usage.rst index 53a2a71..d3ada50 100644 --- a/docs/usage.rst +++ b/docs/usage.rst @@ -20,12 +20,12 @@ you can change the labels after plotting. sns.set() # get prettier plots - truth = ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C'] - prediction = ['A', 'A', 'B', 'B', 'C', 'C', 'A', 'A', 'C'] - label_aliases = {'A': 'c1', 'B': 'c2', 'C': 'c3'} + truth = ["A", "A", "A", "B", "B", "B", "C", "C", "C"] + prediction = ["A", "A", "B", "B", "C", "C", "A", "A", "C"] + label_aliases = {"A": "c1", "B": "c2", "C": "c3"} plt.figure(figsize=[2.8, 2.5]) - plt.title('Confusion Matrix') + plt.title("Confusion Matrix") audplot.confusion_matrix(truth, prediction, label_aliases=label_aliases) plt.tight_layout() @@ -50,7 +50,7 @@ you can specify the axes to draw on. audplot.series, ] fig, axs = plt.subplots(1, len(plot_funcs), figsize=[12, 3]) - plt.suptitle('Multiple plots in one figure') + plt.suptitle("Multiple plots in one figure") for plot_func, ax in zip(plot_funcs, axs): plot_func(truth, prediction, ax=ax) diff --git a/pyproject.toml b/pyproject.toml index 73d695a..a7961c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -77,6 +77,12 @@ addopts = ''' # ----- ruff -------------------------------------------------------------- # [tool.ruff] +cache-dir = '.cache/ruff' + +[tool.ruff.format] +docstring-code-format = true + +[tool.ruff.lint] select = [ 'D', # pydocstyle 'E', # pycodestyle errors @@ -93,11 +99,7 @@ extend-ignore = [ 'D107', # Missing docstring in `__init__` ] -line-length = 79 - -cache-dir = '.cache/ruff' - -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] '__init__.py' = [ 'F401', # * imported but unused ] @@ -111,7 +113,7 @@ cache-dir = '.cache/ruff' # # Check correct order/syntax of import statements # -[tool.ruff.isort] +[tool.ruff.lint.isort] # All from imports have their own line, e.g. # @@ -148,7 +150,7 @@ section-order = [ 'first-party', 'local-folder', ] -[tool.ruff.isort.sections] +[tool.ruff.lint.isort.sections] 'audeering' = [ 'audb', 'audbackend', @@ -173,7 +175,7 @@ section-order = [ # # Check variable/class names follow PEP8 naming convention # -[tool.ruff.pep8-naming] +[tool.ruff.lint.pep8-naming] ignore-names = [ 'config', # allow lowercase class name 'test_*', # allow uppercase name when testing a class @@ -184,7 +186,7 @@ ignore-names = [ # # Check docstrings follow selected convention # -[tool.ruff.pydocstyle] +[tool.ruff.lint.pydocstyle] convention = 'google' diff --git a/tests/test_api.py b/tests/test_api.py index eac0b0c..c0bf74e 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -9,35 +9,35 @@ @pytest.mark.parametrize( - 'number, expected_string', + "number, expected_string", [ - (0, '0'), - (1, '1'), - (10, '10'), - (100, '100'), - (1000, '1k'), - (10000, '10k'), - (100000, '100k'), - (1000000, '1M'), - (0.1, '100m'), - (0.01, '10m'), - (0.001, '1m'), - (0.0015, '1.5m'), - (0.0001, '100u'), - (-1, '-1'), - (-0.001, '-1m'), - (-0.0015, '-1.5m'), + (0, "0"), + (1, "1"), + (10, "10"), + (100, "100"), + (1000, "1k"), + (10000, "10k"), + (100000, "100k"), + (1000000, "1M"), + (0.1, "100m"), + (0.01, "10m"), + (0.001, "1m"), + (0.0015, "1.5m"), + (0.0001, "100u"), + (-1, "-1"), + (-0.001, "-1m"), + (-0.0015, "-1.5m"), pytest.param( - 1000 ** 9, - '', + 1000**9, + "", marks=pytest.mark.xfail(raises=ValueError), ), pytest.param( - 1000 ** -4, - '', + 1000**-4, + "", marks=pytest.mark.xfail(raises=ValueError), ), - ] + ], ) def test_human_format(number, expected_string): string = audplot.human_format(number)