Skip to content

Config

docstring_format_checker.config 🔗

Summary

Configuration handling for the docstring format checker.

GlobalConfig dataclass 🔗

Summary

Global configuration for docstring checking behavior.

Source code in src/docstring_format_checker/config.py
107
108
109
110
111
112
113
114
115
116
@dataclass
class GlobalConfig:
    """
    !!! note "Summary"
        Global configuration for docstring checking behavior.
    """

    allow_undefined_sections: bool = False
    require_docstrings: bool = True
    check_private: bool = False
__init__ 🔗
__init__(
    allow_undefined_sections: bool = False,
    require_docstrings: bool = True,
    check_private: bool = False,
) -> None
allow_undefined_sections class-attribute instance-attribute 🔗
allow_undefined_sections: bool = False
require_docstrings class-attribute instance-attribute 🔗
require_docstrings: bool = True
check_private class-attribute instance-attribute 🔗
check_private: bool = False

SectionConfig dataclass 🔗

Summary

Configuration for a docstring section.

Source code in src/docstring_format_checker/config.py
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
@dataclass
class SectionConfig:
    """
    !!! note "Summary"
        Configuration for a docstring section.
    """

    order: int
    name: str
    type: Literal["free_text", "list_name", "list_type", "list_name_and_type"]
    admonition: Union[bool, str] = False
    prefix: str = ""  # Support any prefix string
    required: bool = False
    message: str = ""  # Optional message for validation errors

    def __post_init__(self) -> None:
        """
        !!! note "Summary"
            Validate configuration after initialization.
        """
        self._validate_types()
        self._validate_admonition_prefix_combination()

    def _validate_types(self) -> None:
        """
        !!! note "Summary"
            Validate the 'type' field.
        """
        if self.type not in VALID_TYPES:
            raise InvalidTypeValuesError(f"Invalid section type: {self.type}. Valid types: {VALID_TYPES}")

    def _validate_admonition_prefix_combination(self) -> None:
        """
        !!! note "Summary"
            Validate admonition and prefix combination rules.
        """

        if isinstance(self.admonition, bool):
            # Rule: admonition cannot be True (only False or string)
            if self.admonition is True:
                raise ValueError(f"Section '{self.name}': admonition cannot be True, must be False or a string")

            # Rule: if admonition is False, prefix cannot be provided
            if self.admonition is False and self.prefix:
                raise ValueError(f"Section '{self.name}': when admonition=False, prefix cannot be provided")

        elif isinstance(self.admonition, str):
            # Rule: if admonition is a string, prefix must be provided
            if not self.prefix:
                raise ValueError(f"Section '{self.name}': when admonition is a string, prefix must be provided")

        else:
            raise ValueError(
                f"Section '{self.name}': admonition must be a boolean or string, got {type(self.admonition)}"
            )
__init__ 🔗
__init__(
    order: int,
    name: str,
    type: Literal[
        "free_text",
        "list_name",
        "list_type",
        "list_name_and_type",
    ],
    admonition: Union[bool, str] = False,
    prefix: str = "",
    required: bool = False,
    message: str = "",
) -> None
order instance-attribute 🔗
order: int
name instance-attribute 🔗
name: str
type instance-attribute 🔗
type: Literal[
    "free_text",
    "list_name",
    "list_type",
    "list_name_and_type",
]
admonition class-attribute instance-attribute 🔗
admonition: Union[bool, str] = False
prefix class-attribute instance-attribute 🔗
prefix: str = ''
required class-attribute instance-attribute 🔗
required: bool = False
message class-attribute instance-attribute 🔗
message: str = ''
__post_init__ 🔗
__post_init__() -> None

Summary

Validate configuration after initialization.

Source code in src/docstring_format_checker/config.py
139
140
141
142
143
144
145
def __post_init__(self) -> None:
    """
    !!! note "Summary"
        Validate configuration after initialization.
    """
    self._validate_types()
    self._validate_admonition_prefix_combination()

Config dataclass 🔗

Summary

Complete configuration containing global settings and section definitions.

Source code in src/docstring_format_checker/config.py
229
230
231
232
233
234
235
236
237
@dataclass
class Config:
    """
    !!! note "Summary"
        Complete configuration containing global settings and section definitions.
    """

    global_config: GlobalConfig
    sections: list[SectionConfig]
__init__ 🔗
__init__(
    global_config: GlobalConfig,
    sections: list[SectionConfig],
) -> None
global_config instance-attribute 🔗
global_config: GlobalConfig
sections instance-attribute 🔗
sections: list[SectionConfig]

DEFAULT_CONFIG module-attribute 🔗

DEFAULT_CONFIG: Config = Config(
    global_config=GlobalConfig(), sections=DEFAULT_SECTIONS
)

load_config 🔗

load_config(
    config_path: Optional[Union[str, Path]] = None,
) -> Config

Summary

Load configuration from a TOML file or return default configuration.

Parameters:

Name Type Description Default
config_path Optional[Union[str, Path]]

Path to the TOML configuration file. If None, looks for pyproject.toml in current directory. Default: None.

None

Raises:

Type Description
FileNotFoundError

If the specified config file doesn't exist.

InvalidConfigError

If the configuration is invalid.

Returns:

Type Description
Config

Configuration object containing global settings and section definitions.

Source code in src/docstring_format_checker/config.py
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
def load_config(config_path: Optional[Union[str, Path]] = None) -> Config:
    """
    !!! note "Summary"
        Load configuration from a TOML file or return default configuration.

    Params:
        config_path (Optional[Union[str, Path]]):
            Path to the TOML configuration file.
            If `None`, looks for `pyproject.toml` in current directory.
            Default: `None`.

    Raises:
        (FileNotFoundError):
            If the specified config file doesn't exist.
        (InvalidConfigError):
            If the configuration is invalid.

    Returns:
        (Config):
            Configuration object containing global settings and section definitions.
    """

    if config_path is None:
        # Look for pyproject.toml in current directory
        pyproject_path: Path = Path.cwd().joinpath("pyproject.toml")
        if pyproject_path.exists():
            config_path = pyproject_path
        else:
            return DEFAULT_CONFIG

    # Convert to Path object and check existence
    config_path = Path(config_path)
    if not config_path.exists():
        raise FileNotFoundError(f"Configuration file not found: {config_path}")

    try:
        with open(config_path, "rb") as f:
            config_data: dict[str, Any] = tomllib.load(f)
    except Exception as e:
        raise InvalidConfigError(f"Failed to parse TOML file {config_path}: {e}") from e

    # Try to find configuration under [tool.dfc] or [tool.docstring-format-checker]
    tool_config = None
    if "tool" in config_data:
        if "dfc" in config_data["tool"]:
            tool_config = config_data["tool"]["dfc"]
        elif "docstring-format-checker" in config_data["tool"]:
            tool_config = config_data["tool"]["docstring-format-checker"]

    if tool_config is None:
        return DEFAULT_CONFIG

    # Parse global configuration flags
    global_config = GlobalConfig(
        allow_undefined_sections=tool_config.get("allow_undefined_sections", False),
        require_docstrings=tool_config.get("require_docstrings", True),
        check_private=tool_config.get("check_private", False),
    )

    # Parse sections configuration
    sections_config: list[SectionConfig] = []
    if "sections" in tool_config:
        sections_data = tool_config["sections"]
        for section_data in sections_data:
            try:
                # Get admonition value with proper default handling
                admonition_value: Union[str, bool] = section_data.get("admonition")
                if admonition_value is None:
                    admonition_value = False  # Use SectionConfig default

                section = SectionConfig(
                    order=section_data.get("order", 0),
                    name=section_data.get("name", ""),
                    type=section_data.get("type", ""),
                    admonition=admonition_value,
                    prefix=section_data.get("prefix", ""),
                    required=section_data.get("required", False),
                )
                sections_config.append(section)
            except (KeyError, TypeError, ValueError, InvalidTypeValuesError) as e:
                raise InvalidConfigError(f"Invalid section configuration: {section_data}. Error: {e}") from e

    # Use default sections if none provided, otherwise validate and sort
    if not sections_config:
        sections_config = DEFAULT_SECTIONS
    else:
        # Validate no duplicate order values
        _validate_config_order(config_sections=sections_config)

        # Sort by order
        sections_config.sort(key=lambda x: x.order)

    return Config(global_config=global_config, sections=sections_config)

find_config_file 🔗

find_config_file(
    start_path: Optional[Path] = None,
) -> Optional[Path]

Summary

Find configuration file by searching up the directory tree.

Parameters:

Name Type Description Default
start_path Optional[Path]

Directory to start searching from. If None, resolves to current directory. Default: None.

None

Returns:

Type Description
Optional[Path]

Path to the configuration file if found, None otherwise.

Source code in src/docstring_format_checker/config.py
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
def find_config_file(start_path: Optional[Path] = None) -> Optional[Path]:
    """
    !!! note "Summary"
        Find configuration file by searching up the directory tree.

    Params:
        start_path (Optional[Path]):
            Directory to start searching from.
            If `None`, resolves to current directory.
            Default: `None`.

    Returns:
        (Optional[Path]):
            Path to the configuration file if found, None otherwise.
    """
    if start_path is None:
        start_path = Path.cwd()

    current_path: Path = start_path.resolve()

    while current_path != current_path.parent:
        pyproject_path: Path = current_path.joinpath("pyproject.toml")
        if pyproject_path.exists():
            # Check if it contains dfc configuration
            try:
                with open(pyproject_path, "rb") as f:
                    config_data: dict[str, Any] = tomllib.load(f)
                    if "tool" in config_data and (
                        "dfc" in config_data["tool"] or "docstring-format-checker" in config_data["tool"]
                    ):
                        return pyproject_path
            except Exception:
                pass

        current_path = current_path.parent

    return None