API Reference

This section contains the API documentation for the pylint-sort-functions plugin.

Checker Module

Main checker class for enforcing function and method sorting.

The FunctionSortChecker is used by PyLint itself, not by end users directly. PyLint discovers this checker via the plugin entry point and manages its lifecycle.

For detailed information about the sorting rules and algorithm, see docs/sorting.rst.

How it works:
  1. PyLint loads the plugin and calls register() function (the plugin entry point defined in __init__.py and configured in pyproject.toml)

  2. register() creates a FunctionSortChecker instance and gives it to PyLint

  3. PyLint walks the AST (Abstract Syntax Tree) of user code

  4. For each AST node, PyLint calls corresponding visit_* methods on this checker (we only implement visit_module and visit_classdef from the many available)

  5. The checker analyzes nodes and calls self.add_message() when issues are found

User Experience:

$ pylint –load-plugins=pylint_sort_functions mycode.py # PyLint automatically uses this checker and reports any sorting violations

The visitor pattern: PyLint calls visit_module() for modules and visit_classdef() for class definitions. Each method analyzes the code structure and reports issues.

class pylint_sort_functions.checker.FunctionSortChecker(linter)

Bases: BaseChecker

Checker to enforce alphabetical sorting of functions and methods.

Inherits from PyLint’s BaseChecker which provides the visitor pattern infrastructure. PyLint will automatically call our visit_* methods as it traverses the AST.

name: str = 'function-sort'

Name of the provider.

msgs: dict[str, Any] = {'W9001': ('Functions are not sorted alphabetically in %s scope', 'unsorted-functions', 'Functions should be organized alphabetically within their scope (public functions first, then private functions with underscore prefix)'), 'W9002': ('Methods are not sorted alphabetically in class %s', 'unsorted-methods', 'Class methods should be organized alphabetically within their visibility scope (public methods first, then private methods with underscore prefix)'), 'W9003': ('Public and private functions are not properly separated in %s', 'mixed-function-visibility', 'Public functions (no underscore prefix) should come before private functions (underscore prefix) with clear separation'), 'W9004': ("Function '%s' should be private (prefix with underscore)", 'function-should-be-private', "Functions that are only used within their defining module should be marked as private by prefixing their name with an underscore. This rule detects functions with helper/utility naming patterns (get_, validate_, process_, helper, etc.) that are called only within the same module. Note: Cannot detect cross-module usage, so functions used by other modules won't be flagged (which reduces false positives)."), 'W9005': ("Function '%s' should be public (remove underscore prefix)", 'function-should-be-public', "Functions that are currently marked as private (underscore prefix) but are used by other modules should be made public by removing the underscore prefix. This rule detects cross-module imports and usage of private functions, indicating they are part of the module's public API."), 'W9006': ("Method '%s' is in wrong section (expected: %s, found: %s)", 'method-wrong-section', "Method appears under an incorrect section header. Methods should be organized under section headers that match their categorization (e.g., test methods under '# Test methods', properties under '# Properties'). Enable section header enforcement with enforce-section-headers=true."), 'W9007': ("Missing section header '%s' for methods in category '%s'", 'missing-section-header', 'A section header is required for methods in this category, but no matching header was found. Add the appropriate section header comment before methods of this type. Enable with require-section-headers=true.'), 'W9008': ("Section header '%s' has no matching methods", 'empty-section-header', 'Section header exists but contains no methods underneath. Either add methods to this section or remove the unnecessary header. Control with allow-empty-sections configuration option.')}
options: Options = (('public-api-patterns', {'default': ['main', 'run', 'execute', 'start', 'stop', 'setup', 'teardown'], 'help': 'List of function names to always treat as public API. These functions will not be flagged for privacy even if only used internally. Useful for entry points and framework callbacks.', 'metavar': '<pattern1,pattern2,...>', 'type': 'csv'}), ('enable-privacy-detection', {'default': True, 'help': 'Enable detection of functions that should be made private based on usage analysis.', 'metavar': '<y or n>', 'type': 'yn'}), ('ignore-decorators', {'default': [], 'help': 'Decorator patterns to exclude from sorting requirements. Supports exact matches and wildcards (e.g., @app.route).', 'metavar': '<pattern1,pattern2,...>', 'type': 'csv'}), ('privacy-exclude-dirs', {'default': [], 'help': 'Directories to exclude from privacy analysis. Files in these directories are scanned but their references are ignored when determining if functions should be private. Useful for test directories and other non-production code.', 'metavar': '<dir1,dir2,...>', 'type': 'csv'}), ('privacy-exclude-patterns', {'default': [], 'help': "File patterns to exclude from privacy analysis. Files matching these patterns are scanned but their references are ignored when determining if functions should be private. Supports glob patterns like 'test_*.py', '*_test.py', 'conftest.py'.", 'metavar': '<pattern1,pattern2,...>', 'type': 'csv'}), ('privacy-additional-test-patterns', {'default': [], 'help': "Additional file patterns to treat as test files, beyond the built-in detection. These patterns are added to the default test detection (test_*.py, *_test.py, conftest.py, tests/). Supports glob patterns like 'spec_*.py', '*_spec.py'.", 'metavar': '<pattern1,pattern2,...>', 'type': 'csv'}), ('privacy-update-tests', {'default': False, 'help': 'Enable automatic updating of test files when functions are privatized. When enabled, test files will be automatically updated to use the new private function names. Requires the privacy fixer to be run.', 'metavar': '<y or n>', 'type': 'yn'}), ('privacy-override-test-detection', {'default': False, 'help': 'Override the built-in test file detection entirely and only use the patterns specified in privacy-exclude-patterns and privacy-exclude-dirs. When disabled, both built-in detection and custom patterns are used together.', 'metavar': '<y or n>', 'type': 'yn'}), ('enable-method-categories', {'default': False, 'help': 'Enable flexible method categorization system. When disabled, uses the original binary public/private sorting. When enabled, allows custom method categories and framework presets.', 'metavar': '<y or n>', 'type': 'yn'}), ('framework-preset', {'default': None, 'help': 'Use a built-in framework preset for method categorization. Available presets: pytest, unittest, pyqt, django. Requires enable-method-categories=true.', 'metavar': '<preset_name>', 'type': 'string'}), ('method-categories', {'default': None, 'help': 'JSON configuration for custom method categories. Defines category names, patterns, decorators, and priorities. Example: \'[{"name":"properties","decorators":["@property"]}]\'', 'metavar': '<json_config>', 'type': 'string'}), ('category-sorting', {'choices': ['alphabetical', 'declaration'], 'default': 'alphabetical', 'help': "How to sort methods within each category. 'alphabetical' sorts methods alphabetically within categories. 'declaration' preserves the original declaration order.", 'metavar': '<alphabetical|declaration>', 'type': 'choice'}), ('enforce-section-headers', {'default': False, 'help': 'Enforce that methods must be organized under correct section headers according to their categorization. When enabled, methods appearing under wrong section headers will trigger warnings. Requires enable-method-categories=true.', 'metavar': '<y or n>', 'type': 'yn'}), ('require-section-headers', {'default': False, 'help': 'Require section headers to be present for each category that contains methods. When enabled, missing section headers will trigger warnings. Requires enforce-section-headers=true.', 'metavar': '<y or n>', 'type': 'yn'}), ('allow-empty-sections', {'default': True, 'help': 'Allow section headers to exist without any methods underneath. When disabled, empty section headers will trigger warnings. Requires enforce-section-headers=true.', 'metavar': '<y or n>', 'type': 'yn'}))

Options provided by this provider.

visit_classdef(node)

Visit a class definition to check method sorting.

Called by PyLint for each class definition in the code.

Parameters:

node (nodes.ClassDef) – The class definition AST node to analyze

Return type:

None

visit_module(node)

Visit a module node to check function sorting and privacy.

Called by PyLint once for each Python module (file) being analyzed.

Parameters:

node (nodes.Module) – The module AST node to analyze

Return type:

None

Messages Module

Message definitions for the pylint-sort-functions plugin.

The MESSAGES dict defines all warning/error codes that this PyLint plugin can report. Each entry creates a new PyLint message that users will see when running PyLint.

Message Structure:
Key: Message ID (e.g., “W9001”)
  • First letter: Severity (W=Warning, E=Error, C=Convention, R=Refactor)

  • Digits: Plugin’s unique range (9001-9999 for custom plugins)

Value: Tuple of (template, symbol, description)
  • Template: Actual message shown to users (supports %s formatting)

  • Symbol: Human-readable name for disabling (e.g., unsorted-functions)

  • Description: Longer explanation for documentation/help

Usage Examples:

In checker: self.add_message(“unsorted-functions”, node=node, args=(“module”,)) PyLint output: W9001: Functions are not sorted alphabetically in module scope (unsorted-functions) User disabling: # pylint: disable=unsorted-functions

Utilities Module

Utility functions for AST analysis and sorting logic.

This module provides the core analysis functions for the pylint-sort-functions plugin. Refactored from a single 1117-line file into focused modules for better maintainability.

For backward compatibility, all public functions are re-exported from their specialized modules. All existing imports continue to work unchanged.

For detailed information about the sorting algorithm and rules, see the documentation at docs/sorting.rst which explains the complete sorting methodology, special method handling, privacy detection, and configuration options.

Function Privacy Detection: The plugin uses import analysis to identify functions that should be private by scanning actual usage patterns across the project: - Analyzes cross-module imports and function calls in all Python files - Identifies functions that are only used within their own module - Skips common public API patterns (main, run, setup, etc.) - Provides accurate detection based on real usage patterns

class pylint_sort_functions.utils.CategoryConfig(categories=<factory>, default_category='public_methods', enable_categories=False, category_sorting='alphabetical')

Bases: object

Configuration for the method categorization system.

Defines the complete categorization scheme including all categories, default behavior, and compatibility settings.

Parameters:
  • categories (list[MethodCategory]) – List of method categories in sorting order

  • default_category (str) – Category name for methods that do not match patterns

  • enable_categories (bool) – Enable multi-category system (false = backward compatibility)

  • category_sorting (str) – How to sort within categories (‘alphabetical’ or ‘declaration’)

__init__(categories=<factory>, default_category='public_methods', enable_categories=False, category_sorting='alphabetical')
category_sorting: str = 'alphabetical'
default_category: str = 'public_methods'
enable_categories: bool = False
categories: list[MethodCategory]
class pylint_sort_functions.utils.MethodCategory(name, patterns=<factory>, decorators=<factory>, priority=0, section_header='')

Bases: object

Configuration for a method category in the sorting system.

Defines how methods are categorized based on patterns, decorators, and other criteria. Categories determine the sorting order and section organization.

Parameters:
  • name (str) – Unique identifier for this category (e.g., ‘properties’)

  • patterns (list[str]) – List of glob patterns to match names (e.g., [‘test_*’])

  • decorators (list[str]) – List of decorator patterns (e.g., [@property’])

  • priority (int) – Priority for conflict resolution, higher values win

  • section_header (str) – Comment header text for this category

__init__(name, patterns=<factory>, decorators=<factory>, priority=0, section_header='')
priority: int = 0
section_header: str = ''
name: str
patterns: list[str]
decorators: list[str]
pylint_sort_functions.utils.are_functions_properly_separated(functions)

Check if public and private functions are properly separated.

This function only verifies the ordering constraint: public functions must appear before private functions. It does not check for section comment headers like “# Public functions” or “# Private functions” - that would be a separate validation if implemented.

Parameters:

functions (list[nodes.FunctionDef]) – List of function definition nodes

Returns:

True if public functions come before private functions

Return type:

bool

pylint_sort_functions.utils.are_functions_sorted_with_exclusions(functions, ignore_decorators=None, config=None)

Check if functions are sorted alphabetically, excluding decorator-dependent ones.

This is the enhanced version of _are_functions_sorted that supports framework-aware sorting by excluding functions with specific decorators that create dependencies.

Parameters:
  • functions (list[nodes.FunctionDef]) – List of function definition nodes

  • ignore_decorators (list[str] | None) – List of decorator patterns to ignore

  • config (CategoryConfig | None) – Category configuration, uses default if None

Returns:

True if functions are properly sorted (excluding ignored ones)

Return type:

bool

pylint_sort_functions.utils.are_methods_in_correct_sections(methods, lines, config)

Check if methods are positioned in their correct sections.

Validates that all methods appear under the appropriate section headers according to their categorization. This makes section headers functional rather than just decorative.

Parameters:
  • methods (list[nodes.FunctionDef]) – List of method nodes to validate

  • lines (list[str]) – Source code lines containing the methods

  • config (CategoryConfig) – Category configuration with section headers

Returns:

True if all methods are in correct sections

Return type:

bool

pylint_sort_functions.utils.are_methods_sorted_with_exclusions(methods, ignore_decorators=None, config=None)

Check if methods are sorted alphabetically, excluding decorator-dependent ones.

Parameters:
  • methods (list[nodes.FunctionDef]) – List of method definition nodes

  • ignore_decorators (list[str] | None) – List of decorator patterns to ignore

  • config (CategoryConfig | None) – Category configuration, uses default if None

Returns:

True if methods are properly sorted (excluding ignored ones)

Return type:

bool

pylint_sort_functions.utils.categorize_method(func, config=None)

Determine the category for a method based on configuration patterns.

This replaces the binary is_private_function() with a flexible categorization system that supports multiple method types (properties, test methods, etc.).

When enable_categories=False (default), provides backward compatible behavior by returning ‘public_methods’ or ‘private_methods’ based on naming convention.

Parameters:
  • func (nodes.FunctionDef) – Function definition node to categorize

  • config (CategoryConfig | None) – Category configuration, uses default if None

Returns:

Category name for the method (e.g., ‘properties’, ‘test_methods’)

Return type:

str

pylint_sort_functions.utils.decorator_matches_pattern(decorator_str, pattern)

Check if a decorator string matches an ignore pattern.

Supports exact matches and simple wildcard patterns. This allows users to exclude functions with specific decorators from sorting requirements when the decorators create ordering dependencies.

Examples: - “@app.route” matches both @app.route and @app.route(“/path”) - “@*.command” matches @main.command(), @cli.command(), etc.

Parameters:
  • decorator_str (str) – Decorator string to check (e.g., “@main.command()”)

  • pattern (str) – Pattern to match against (e.g., “@main.command”, “@*.command”)

Returns:

True if decorator matches the pattern

Return type:

bool

pylint_sort_functions.utils.find_empty_section_headers(methods, lines, config)

Find section headers that exist but have no methods underneath.

Identifies section headers that are present in the source code but have no corresponding methods in that category.

Parameters:
  • methods (list[nodes.FunctionDef]) – List of method nodes to analyze

  • lines (list[str]) – Source code lines to check for headers

  • config (CategoryConfig) – Category configuration with section headers

Returns:

List of empty section header category names

Return type:

list[str]

pylint_sort_functions.utils.find_method_section_boundaries(lines, config)

Map line numbers to their section categories based on headers.

Creates a mapping from line numbers to category names, where each line between section headers belongs to the category of the preceding header.

Parameters:
  • lines (list[str]) – Source code lines to analyze

  • config (CategoryConfig) – Category configuration with section headers

Returns:

Dict mapping line numbers to category names

Return type:

dict[int, str]

pylint_sort_functions.utils.find_missing_section_headers(methods, lines, config)

Find section headers that should exist but are missing.

Analyzes methods to determine which categories have methods but no corresponding section header in the source code.

Parameters:
  • methods (list[nodes.FunctionDef]) – List of method nodes to analyze

  • lines (list[str]) – Source code lines to check for headers

  • config (CategoryConfig) – Category configuration with section headers

Returns:

List of missing section header category names

Return type:

list[str]

pylint_sort_functions.utils.find_python_files(root_path)

Find all Python files in a project directory.

Recursively searches for files with .py extension while skipping common directories that should not be analyzed (build artifacts, virtual environments, caches, etc.).

TODO: Make skip_dirs list configurable for project-specific needs.

Parameters:

root_path (Path) – Root directory to search for Python files

Returns:

List of paths to Python files

Return type:

list[Path]

pylint_sort_functions.utils.function_has_excluded_decorator(func, ignore_decorators)

Check if a function should be excluded from sorting due to its decorators.

Some decorators create dependencies that make alphabetical sorting inappropriate. For example, Click commands or Flask routes may need specific ordering for proper framework behavior.

Parameters:
  • func (nodes.FunctionDef) – Function definition node to check

  • ignore_decorators (list[str] | None) – List of decorator patterns to match against

Returns:

True if function should be excluded from sorting requirements

Return type:

bool

pylint_sort_functions.utils.get_decorator_strings(func)

Extract string representations of all decorators on a function.

Parameters:

func (nodes.FunctionDef) – Function definition node

Returns:

List of decorator strings (e.g., [“@main.command()”, “@app.route()”])

Return type:

list[str]

pylint_sort_functions.utils.get_expected_section_for_method(method, config)

Get expected section name for a method based on categorization.

Uses the categorization system to determine which section header a method should appear under according to the configuration.

Parameters:
  • method (nodes.FunctionDef) – Method node to analyze

  • config (CategoryConfig) – Category configuration

Returns:

Expected category/section name for this method

Return type:

str

pylint_sort_functions.utils.get_functions_from_node(node)

Extract all function definitions from a module.

Parameters:

node (nodes.Module) – Module AST node

Returns:

List of function definition nodes

Return type:

list[nodes.FunctionDef]

pylint_sort_functions.utils.get_methods_from_class(node)

Extract all method definitions from a class.

Parameters:

node (nodes.ClassDef) – Class definition node

Returns:

List of method definition nodes

Return type:

list[nodes.FunctionDef]

pylint_sort_functions.utils.get_section_violations(methods, lines, config)

Get detailed information about methods in wrong sections.

Returns a list of violations where methods are not in their expected sections, including the expected and actual section information.

Parameters:
  • methods (list[nodes.FunctionDef]) – List of method nodes to analyze

  • lines (list[str]) – Source code lines containing the methods

  • config (CategoryConfig) – Category configuration with section headers

Returns:

List of (method, expected_section, actual_section) tuples

Return type:

list[tuple[nodes.FunctionDef, str, str]]

pylint_sort_functions.utils.is_dunder_method(func)

Check if a function is a dunder/magic method.

Dunder methods are special methods that start and end with double underscores, like __init__, __str__, __call__, etc.

Parameters:

func (nodes.FunctionDef) – Function definition node

Returns:

True if function is a dunder method

Return type:

bool

pylint_sort_functions.utils.is_method_in_correct_section(method, method_line, lines, config)

Check if a method is positioned in its correct section.

Validates that a method appears under the appropriate section header according to its categorization.

Parameters:
  • method (nodes.FunctionDef) – Method node to validate

  • method_line (int) – Line number where method is defined (0-based)

  • lines (list[str]) – Source code lines

  • config (CategoryConfig) – Category configuration

Returns:

True if method is in correct section, False otherwise

Return type:

bool

pylint_sort_functions.utils.is_private_function(func)

Check if a function is private (starts with underscore).

DEPRECATED: This function is maintained for backward compatibility. New code should use categorize_method() with appropriate configuration.

Functions starting with a single underscore are considered private by convention. Dunder methods (double underscore) like __init__ are not considered private as they are special methods with specific meanings in Python.

Parameters:

func (nodes.FunctionDef) – Function definition node

Returns:

True if function name starts with underscore but not double underscore

Return type:

bool

pylint_sort_functions.utils.is_unittest_file(module_name, privacy_config=None)

Check if a module name indicates a unit test file.

Detects test files based on configurable patterns and built-in heuristics. Can be configured to override built-in detection or add additional patterns.

Built-in detection patterns: - Files in ‘tests’ or ‘test’ directories - Files starting with ‘test_’ - Files ending with ‘_test’ - conftest.py files (pytest configuration) - Files containing ‘test’ in their path components

Parameters:
  • module_name (str) – The module name to check (e.g., ‘package.tests.test_utils’)

  • privacy_config (dict[str, Any] | None) – Privacy configuration with exclusion patterns

Returns:

True if module appears to be a test file

Return type:

bool

pylint_sort_functions.utils.parse_section_headers(lines, config)

Parse existing section headers and map them to categories.

Scans source code lines to find comment lines that match section header patterns for any of the configured categories. Returns a mapping from category names to their header line numbers and text.

Parameters:
  • lines (list[str]) – Source code lines to scan for headers

  • config (CategoryConfig) – Category configuration with header patterns

Returns:

Dict mapping category names to (line_number, header_text) tuples

Return type:

dict[str, tuple[int, str]]

pylint_sort_functions.utils.should_function_be_private(func, module_path, project_root, public_patterns=None, privacy_config=None)

Detect if a function should be private based on import analysis.

Analyzes actual usage patterns across the project to determine if a function is only used within its own module and should therefore be made private.

Detection Logic: 1. Skip if already private (starts with underscore) 2. Skip special methods (__init__, __str__, etc.) 3. Skip configurable public API patterns (main, run, setup, etc.) 4. Check if function is imported/used by other modules 5. If not used externally, suggest making it private

Parameters:
  • func (nodes.FunctionDef) – Function definition node to analyze

  • module_path (Path) – Path to the module file

  • project_root (Path) – Root directory of the project

  • public_patterns (set[str] | None) – Set of function names to always treat as public. If None, uses default patterns (main, run, execute, etc.)

Returns:

True if the function should be marked as private

Return type:

bool

pylint_sort_functions.utils.should_function_be_public(func, module_path, project_root, privacy_config=None)

Detect if a private function should be public based on external usage analysis.

Analyzes actual usage patterns across the project to determine if a function that is currently marked as private is actually used by other modules and should therefore be made public.

Detection Logic: 1. Skip if already public (does not start with underscore) 2. Skip special methods (dunder methods like __init__, __str__, etc.) 3. Check if the private function is imported/used by other modules 4. If used externally, suggest making it public

Parameters:
  • func (nodes.FunctionDef) – Function definition node to analyze

  • module_path (Path) – Path to the module file

  • project_root (Path) – Root directory of the project

Returns:

True if the function should be made public

Return type:

bool

Plugin Registration

PyLint plugin to enforce alphabetical sorting of functions and methods.

pylint_sort_functions.register(linter)

Register the plugin with PyLint.

This function is called by PyLint when the plugin is loaded. It registers the FunctionSortChecker with the linter.

Note: This function must remain public as it’s a required PyLint plugin entry point.

Parameters:

linter (PyLinter) – The PyLint linter instance

Return type:

None