Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ coverage.xml
.hypothesis/
.pytest_cache/
cover/
*.lcov

# Translations
*.mo
Expand Down
4 changes: 4 additions & 0 deletions Justfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
SOURCE_PATH := "def_form"
TESTS_PATH := "tests"

default:
@just --list

upgrade:
uv lock --upgrade

Expand All @@ -20,5 +23,6 @@ tests:
uv run pytest \
--cov=def_form \
--cov-report=lcov:tests.lcov \
--cov-report=term \
tests/

134 changes: 107 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
# def-form
<div style="padding-top: 30px; text-align: center;">
<img src="https://raw.githubusercontent.com/TopNik073/def-form/main/assets/logo-transparent.png" alt="def-form logo" width="300">

Python function definition formatter
<p style="margin: 0; font-size: 18px;">Python function definition formatter</p>

[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![PyPI](https://img.shields.io/pypi/v/def-form.svg)](https://pypi.python.org/pypi/def-form)
[![PyPI](https://img.shields.io/pypi/dm/def-form.svg)](https://pypi.python.org/pypi/def-form)
[![Coverage Status](https://coveralls.io/repos/github/TopNik073/def-form/badge.svg?branch=init)](https://coveralls.io/github/TopNik073/def-form?branch=init)

</div>

[![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
[![PyPI](https://img.shields.io/pypi/v/def-form.svg)](https://pypi.python.org/pypi/def-form)
[![PyPI](https://img.shields.io/pypi/dm/def-form.svg)](https://pypi.python.org/pypi/def-form)
[![Coverage Status](https://coveralls.io/repos/github/TopNik073/def-form/badge.svg?branch=init)](https://coveralls.io/github/TopNik073/def-form?branch=init)
## Overview

`def-form` is a code formatting tool that focuses specifically on Python function definitions. It helps maintain consistent formatting of function signatures by automatically organizing arguments vertically when they exceed specified thresholds.
Expand Down Expand Up @@ -47,38 +51,114 @@ def-form format my_module.py
def-form check src/
```

### Command line options
### Example

You can check your code with `check` command and see the result

```text
(.venv) user@MacBook-Pro def-form % def-form check test_file.py
Checking test_file.py

Configuration
─────────────────────────────────────────────────────────────────
Config Path: /Users/user/Documents/def-form/pyproject.toml
Max Inline Args: 2
Max Def Length: 100
Indent Size: 4 spaces
Show Skipped: No
Excluded: .venv, tests/cases, build
─────────────────────────────────────────────────────────────────

Found 1 errors in 1 files

/Users/user/Documents/def-form/test_file.py:19
• Invalid multiline function parameters indentation (expected 4 spaces)

Summary
───────────────────────────
Files processed: 1
Files with issues: 1
Total errors: 1
Success rate: 0.0%
───────────────────────────

Code style violations found
```

Or use `format`
```text
(.venv) user@MacBook-Pro def-form % def-form format test_file.py
Formatting test_file.py

Configuration
─────────────────────────────────────────────────────────────────
Config Path: /Users/user/Documents/def-form/pyproject.toml
Max Inline Args: 2
Max Def Length: 100
Indent Size: 4 spaces
Show Skipped: No
Excluded: build, .venv, tests/cases
─────────────────────────────────────────────────────────────────

Found 1 errors in 1 files

/Users/user/Documents/def-form/test_file.py:19
• Invalid multiline function parameters indentation (expected 4 spaces)

Summary
───────────────────────────
Files processed: 1
Files with issues: 1
Total errors: 1
Success rate: 0.0%
───────────────────────────

Formatting completed
```

## Command line options

There is global options

```text
def-form format [OPTIONS] [PATH]
Usage: def-form [OPTIONS] COMMAND [ARGS]...

Options:
--max-def-length INTEGER Maximum length of function definition
--max-inline-args INTEGER Maximum number of inline arguments
--indent-size INTEGER indent size in spaces (default: 4)
--exclude TEXT Paths or files to exclude from checking/formatting
--show-skipped Show skipped files/directories
--config TEXT Path to pyproject.toml configuration file
--verbose Enable verbose output
--quiet Disable all output
--help Show this message and exit.

Commands:
check
format
```

And specific options for check/format

```text
Usage: def-form format [OPTIONS] [PATH]

Options:
--config FILE Path to pyproject.toml configuration file
--show-skipped Show skipped files and directories
--exclude PATH Paths to exclude from processing
--indent-size INTEGER Indent size in spaces (default: 4)
--max-inline-args INTEGER Maximum number of inline arguments
--max-def-length INTEGER Maximum length of function definition
--help Show this message and exit.
```

### Configuration
## Configuration

Create a pyproject.toml file in your project root:

```toml
[tool.def-form]
max_def_length = 100
max_inline_args = 2
indent_size = 4
exclude = [
max_def_length = 100 # Maximum allowed characters in a single-line function definition
max_inline_args = 2 # Maximum number of arguments allowed in inline format
indent_size = 4 # Indent for arguments in spaces
exclude = [ # Files or directories you want to exclude
'.venv',
'migrations'
]
```

### Configuration options

* max_def_length: Maximum allowed characters in a single-line function definition
* max_inline_args: Maximum number of arguments allowed in inline format
* indent_size: Indent for arguments in spaces
* exclude: Files or directories you want to exclude
```
Binary file added assets/logo-transparent.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 0 additions & 78 deletions def_form/cli/cli.py

This file was deleted.

Empty file.
42 changes: 42 additions & 0 deletions def_form/cli/commands/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import click

from def_form.cli.commands.options import common_options
from def_form.cli.console import RichConsole
from def_form.cli.context import context
from def_form.cli.errors import CheckFailedError
from def_form.cli.ui.rich import RichUI
from def_form.exceptions.base import BaseDefFormException
from def_form.core import DefManager


@click.command()
@common_options
def check( # noqa: PLR0913
path: str,
max_def_length: int | None,
max_inline_args: int | None,
indent_size: int | None,
config: str | None,
exclude: tuple[str, ...],
show_skipped: bool,
) -> None:
console = RichConsole(context=context)
console.info(f'Checking [bold]{path}[/bold]')

try:
DefManager(
path=path,
excluded=exclude,
max_def_length=max_def_length,
max_inline_args=max_inline_args,
indent_size=indent_size,
config=config,
show_skipped=show_skipped,
ui=RichUI(console=console),
).check()
except BaseDefFormException as exc:
raise CheckFailedError('Code style violations found') from exc
except Exception as exc:
raise CheckFailedError(str(exc)) from exc

console.success('All checks passed')
41 changes: 41 additions & 0 deletions def_form/cli/commands/format.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import click

from def_form.cli.commands.options import common_options
from def_form.cli.console import RichConsole
from def_form.cli.context import context
from def_form.cli.errors import FormatterFailedError
from def_form.cli.ui.rich import RichUI
from def_form.core import DefManager


@click.command()
@common_options
def format( # noqa: PLR0913
path: str,
max_def_length: int | None,
max_inline_args: int | None,
indent_size: int | None,
config: str | None,
exclude: tuple[str, ...],
show_skipped: bool,
) -> None:
context.show_skipped = show_skipped
console = RichConsole(context=context)
console.info(f'Formatting [bold]{path}[/bold]')
console.debug('Initializing formatter')

try:
DefManager(
path=path,
excluded=exclude,
max_def_length=max_def_length,
max_inline_args=max_inline_args,
indent_size=indent_size,
config=config,
show_skipped=show_skipped,
ui=RichUI(console=console),
).format()
except Exception as exc:
raise FormatterFailedError(str(exc)) from exc

console.success('Formatting completed')
46 changes: 46 additions & 0 deletions def_form/cli/commands/options.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from collections.abc import Callable

import click


def path_option(func: Callable) -> Callable:
return click.argument('path', type=click.Path(exists=True), default='.')(func)


def max_def_length_option(func: Callable) -> Callable:
return click.option('--max-def-length', type=int, default=None, help='Maximum length of function definition')(func)


def max_inline_args_option(func: Callable) -> Callable:
return click.option('--max-inline-args', type=int, default=None, help='Maximum number of inline arguments')(func)


def indent_size_option(func: Callable) -> Callable:
return click.option('--indent-size', type=int, default=None, help='Indent size in spaces (default: 4)')(func)


def config_option(func: Callable) -> Callable:
return click.option(
'--config',
type=click.Path(exists=True, dir_okay=False),
default=None,
help='Path to pyproject.toml configuration file',
)(func)


def exclude_option(func: Callable) -> Callable:
return click.option('--exclude', multiple=True, type=click.Path(), help='Paths to exclude from processing')(func)


def show_skipped_option(func: Callable) -> Callable:
return click.option('--show-skipped', is_flag=True, default=False, help='Show skipped files and directories')(func)


def common_options(func: Callable) -> Callable:
func = path_option(func)
func = max_def_length_option(func)
func = max_inline_args_option(func)
func = indent_size_option(func)
func = exclude_option(func)
func = show_skipped_option(func)
return config_option(func)
Loading