Skip to content

Linting improvements #54

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Jul 3, 2024
93 changes: 93 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,97 @@ show_missing = true
skip_covered = true

[tool.ruff]
target-version = "py310"
line-length=120
show-fixes = true

[tool.ruff.lint]
ignore = [
"ANN101",
"ANN102",
"EM101",
"TRY003", # Disable until we start creating proper exception classes
"PT011", # Disable until we start creating proper exception classes
"PTH123", # Not using open() to open files
]
select = [
"A", # Builtins
"ANN", # Annotations
"ARG", # Unused arguments
"B", # Bugbear
"BLE", # Blind except
"C4", # Comprehensions
"C90", # mccabe
"COM", # Commas
"D",
"D1", # Undocumented public elements
"D2", # Docstring conventions
"D3", # Triple double quotes
"D4", # Docstring text format
"DTZ", # Datetimes
"EM", # Error messages
"ERA", # Commented-out code
"EXE", # Executable
"F", # Pyflakes
"FA", # __future__ annotations
"FLY", # F-strings
# "FURB", # Refurb
"G", # Logging format
"I", # Isort
"ICN", # Import conventions
"INP", # Disallow PEP-420 (Implicit namespace packages)
"INT", # gettext
"ISC", # Implicit str concat
# "LOG", # Logging
"N", # PEP-8 Naming
"NPY", # Numpy
"PERF", # Unnecessary performance costs
"PGH", # Pygrep hooks
"PIE", # Unnecessary code
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider reviewing the max-args setting.

The max-args setting is quite high at 15. Review if this can be reduced to improve function readability and maintainability.

"PL", # Pylint
"PT", # Pytest
"PTH", # Use Pathlib
"PYI", # Stub files
"Q", # Quotes
"RET", # Return
"RUF", # Ruff
"RSE", # Raise
"S", # Bandit
"SIM", # Code simplification
"SLF", # Private member access
"SLOT", # __slots__
"T10", # Debugger
"T20", # Print
"TCH", # Type checking
"TID", # Tidy imports
"TRY", # Exception handling
"UP", # Pyupgrade
"W", # Warnings
"YTT", # sys.version
]


[tool.ruff.lint.per-file-ignores]
# https://beta.ruff.rs/docs/rules/
"__init__.py" = ["F401","F403","F405",]
"tests/*" = ["ANN", "ARG", "INP001", "S101", "SLF001"]

[tool.ruff.lint.pylint]
max-args = 15
max-branches = 20
max-returns = 10
max-statements = 80

[tool.ruff.lint.flake8-tidy-imports]
ban-relative-imports = "all"

[tool.ruff.lint.flake8-quotes]
docstring-quotes = "double"
multiline-quotes = "double"

[tool.ruff.lint.mccabe]
# Unlike Flake8, default to a complexity level of 10.
max-complexity = 10

[tool.ruff.lint.pydocstyle]
convention = "google"
41 changes: 22 additions & 19 deletions pyretailscience/cross_shop.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
"""This module contains the CrossShop class that is used to create a cross-shop diagram."""

import matplotlib.pyplot as plt
import pandas as pd
from matplotlib.axes import Axes, SubplotBase
from matplotlib_set_diagrams import EulerDiagram, VennDiagram

from pyretailscience.data.contracts import CustomContract, build_expected_columns, build_non_null_columns
from pyretailscience.style.graph_utils import GraphStyles as gs
from pyretailscience.style.graph_utils import GraphStyles
from pyretailscience.style.tailwind import COLORS


class CrossShop:
"""A class to create a cross-shop diagram."""

def __init__(
self,
df: pd.DataFrame,
Expand Down Expand Up @@ -47,7 +51,8 @@ def __init__(
extended_expectations=build_non_null_columns(columns=required_cols),
)
if contract.validate() is False:
raise ValueError(f"The dataframe requires the columns {required_cols} and they must be non-null")
msg = f"The dataframe requires the columns {required_cols} and they must be non-null"
raise ValueError(msg)

self.group_count = 2 if group_3_idx is None else 3

Expand Down Expand Up @@ -95,7 +100,6 @@ def _calc_cross_shop(
Raises:
ValueError: If the groups are not mutually exclusive.
"""

if isinstance(group_1_idx, list):
group_1_idx = pd.Series(group_1_idx)
if isinstance(group_2_idx, list):
Expand Down Expand Up @@ -124,9 +128,7 @@ def _calc_cross_shop(

kpi_df = df.groupby("customer_id")[value_col].agg(agg_func)

cs_df = cs_df.merge(kpi_df, left_index=True, right_index=True)

return cs_df
return cs_df.merge(kpi_df, left_index=True, right_index=True)

@staticmethod
def _calc_cross_shop_table(
Expand Down Expand Up @@ -177,7 +179,7 @@ def plot(
vary_size: bool = False,
figsize: tuple[int, int] | None = None,
ax: Axes | None = None,
**kwargs,
**kwargs: dict[str, any],
) -> SubplotBase:
"""Plot the cross-shop diagram.

Expand All @@ -188,15 +190,16 @@ def plot(
False.
figsize (tuple[int, int], optional): The size of the plot. Defaults to None.
ax (Axes, optional): The axes to plot on. Defaults to None.
**kwargs: Additional keyword arguments to pass to the diagram.
**kwargs (dict[str, any]): Additional keyword arguments to pass to the diagram.

Returns:
SubplotBase: The axes of the plot.
"""
three_circles = 3

zero_group = (0, 0)
colors = [COLORS["green"][500], COLORS["green"][800]]
if self.group_count == 3:
if self.group_count == three_circles:
zero_group = (0, 0, 0)
colors += [COLORS["green"][200]]

Expand Down Expand Up @@ -229,24 +232,24 @@ def plot(
)

for text in diagram.set_label_artists:
text.set_fontproperties(gs.POPPINS_REG)
text.set_fontsize(gs.DEFAULT_AXIS_LABEL_FONT_SIZE)
if self.group_count == 3 and not vary_size:
text.set_fontproperties(GraphStyles.POPPINS_REG)
text.set_fontsize(GraphStyles.DEFAULT_AXIS_LABEL_FONT_SIZE)
if self.group_count == three_circles and not vary_size:
# Increase the spacing between text and the diagram to avoid overlap
self.translate_text_outward(text)

for subset_id, _ in subset_sizes.items():
for subset_id in subset_sizes:
if subset_id not in diagram.subset_label_artists:
continue
text = diagram.subset_label_artists[subset_id]
text.set_fontproperties(gs.POPPINS_REG)
text.set_fontproperties(GraphStyles.POPPINS_REG)

if title is not None:
ax.set_title(
title,
fontproperties=gs.POPPINS_SEMI_BOLD,
fontsize=gs.DEFAULT_TITLE_FONT_SIZE,
pad=gs.DEFAULT_TITLE_PAD + 20,
fontproperties=GraphStyles.POPPINS_SEMI_BOLD,
fontsize=GraphStyles.DEFAULT_TITLE_FONT_SIZE,
pad=GraphStyles.DEFAULT_TITLE_PAD + 20,
)

if source_text is not None:
Expand All @@ -256,8 +259,8 @@ def plot(
xycoords="axes fraction",
ha="left",
va="center",
fontsize=gs.DEFAULT_SOURCE_FONT_SIZE,
fontproperties=gs.POPPINS_LIGHT_ITALIC,
fontsize=GraphStyles.DEFAULT_SOURCE_FONT_SIZE,
fontproperties=GraphStyles.POPPINS_LIGHT_ITALIC,
color="dimgray",
)

Expand Down
Loading
Loading