Purpose¶
When each module contains one primary class, keeping the filename in sync with the class name makes it immediately obvious what a file exports. This rule requires the module filename (without the .py extension) to be the snake_case form of the primary class name in that file.
Configuration¶
rules:
- name: domain-module-naming
description: Module filename must match the primary class name in snake_case
type: module
naming: { source: class_name, transform: snake_case }
apply:
- name: domain-layer
rules: [domain-module-naming]
modules: contexts.*.domain
Violation Example¶
# contexts/catalog/domain/custom.py ← filename does not match class name
class CustomObject:
pass
Passing Example¶
# contexts/catalog/domain/custom_object.py ← matches CustomObject in snake_case
class CustomObject:
pass
Output¶
$ pnl check
contexts/catalog/domain/custom.py:1
[domain-module-naming] Module filename must match the primary class name in snake_case
custom (expected: custom_object)
Found 1 violation(s).
Variant: Outbound Adapters (Qualifier in the Directory)¶
Outbound adapters name the module after the port they implement and let the
directory carry the technology — postgres/organization_repository.py holds
class PostgresOrganizationRepository. Use match: suffix so the filename can be
a trailing slice of the class name, and strip_prefix: parent_dir so the dropped
qualifier must equal the parent directory.
rules:
- name: outbound-module-naming
description: Outbound adapter filename is the port name; technology lives in the directory
type: module
naming:
source: class_name
transform: snake_case
match: suffix
strip_prefix: parent_dir
apply:
- name: outbound-adapters
rules: [outbound-module-naming]
modules: contexts.*.adapters.outbound
Passing: persistence/postgres/organization_repository.py with
PostgresOrganizationRepository. Violations: duplicating the qualifier in the
filename (postgres/postgres_organization_repository.py), placing the qualifier
in the filename with no matching directory (httpx_image_fetcher.py), or
inverting the layout so the filename is the technology and the directory is the
port (property_sync_fetcher/google_sheet.py).