6.1. ats_linter package

6.1.1. Submodules

6.1.2. ats_linter.ast_test_module_factory module

Copyright (c) 2023 Aydin Abdi.

ASTTestModuleFactory is a factory class for creating test modules based on Python’s AST (Abstract Syntax Tree). It encapsulates the logic of parsing an AST from a Python test file, extracting test module, classes, cases, and pytest fixtures. Test cases are based on unittest.TestCase and pytest test functions and fixtures based on pytest fixtures.

class ats_linter.ast_test_module_factory.ASTTestModuleFactory[source]

Bases: object

Test module factory based on Python’s AST (Abstract Syntax Tree).

This class encapsulates the logic of parsing an AST from a Python test file, extracting test module, classes, cases, and pytest fixtures. Test cases are based on unittest.TestCase and pytest test functions and fixtures based on pytest fixtures.

static extract_entities(nodes: list[AST], entity_class: Entity, condition: Callable[[AST], bool]) Sequence[Entity][source]

Extract entities of a given type from the list of nodes.

Parameters:
  • nodes – A list of AST nodes to extract entities from.

  • entity_class – The class of the entity to extract.

  • condition – A function that defines the condition for entity extraction.

Returns:

A list of entity instances extracted from the nodes.

static get_function_nodes(nodes: list[AST]) list[FunctionDef][source]

Get function nodes from a list of AST nodes.

Parameters:

nodes – The list of AST nodes.

Returns:

The function nodes from the list of nodes.

static get_test_classes(nodes: list[AST]) list[ClassDef][source]

Get test classes from a list of AST nodes.

Parameters:

nodes – The list of AST nodes.

Returns:

The test classes from the list of nodes.

static is_pytest_fixture(node: AST) bool[source]

Check if a node is a pytest fixture.

Parameters:

node – The node to check.

Returns:

Boolean value indicating whether the node is a pytest fixture.

static is_test_case(node: AST) bool[source]

Check if a node is a test case.

Parameters:

node – The node to check.

Returns:

Boolean value indicating whether the node is a test case.

static parse_test_classes(test_classes: list[ClassDef]) list[TestClass][source]

Parse test classes.

Parameters:

test_classes – The test classes to parse.

Returns:

The parsed test classes.

6.1.3. ats_linter.async_ast_parser module

Copyright (c) 2023 Aydin Abdi.

ASTProducer reads files and produces AST(Abstract Syntax Tree)s.

class ats_linter.async_ast_parser.ASTConsumer(ast_tree_queue: Queue, test_modules: list[TestModule])[source]

Bases: object

Parse ASTs into TestModule objects.

This class encapsulates the logic of parsing ASTs into TestModule objects. The ASTs are consumed asynchronously from a queue.

Parameters:
  • ast_tree_queue (The queue of ASTs produced from the Python files.)

  • test_modules (The queue of TestModule objects produced from the ASTs.)

  • task (The asyncio task that consumes the ASTs.)

ast_tree_queue: Queue
async consume_ast_trees() None[source]

Consume ASTs from the queue and parse them into TestModule objects.

This method consumes ASTs from the queue and parses them into TestModule objects. The method will stop consuming ASTs when it encounters the sentinel value.

parse_ast_tree(module_name: Path, ast_tree: Module) TestModule[source]

Parse an AST into a TestModule object.

Parameters:
  • module_name – Path to the module.

  • ast_tree – The AST of the module.

Returns:

class: TestModule object.

Return type:

The

task: Task | None = None
test_modules: list[TestModule]
class ats_linter.async_ast_parser.ASTProducer(file_paths: list[~pathlib.Path], ast_tree_queue: ~asyncio.queues.Queue = <factory>)[source]

Bases: object

Read files and produce AST(Abstract Syntax Tree)s.

This class encapsulates the logic of reading Python files and producing ASTs. The ASTs are produced asynchronously and put in a queue.

Parameters:
  • file_paths (The list of :class: Path objects of the Python files to parse.)

  • ast_tree_queue (The queue of ASTs produced from the Python files.)

  • task (The asyncio task that produces the ASTs.)

ast_tree_queue: Queue
file_paths: list[Path]
static is_test_file(file_path: Path) bool[source]

Check if file is a test module.

Parameters:

file_path – The path of the file to check.

Returns:

Boolean value indicating whether the file is a test module.

async produce_ast_trees() None[source]

Produce ASTs from the Python files.

This method reads the Python files and produces ASTs from them.

task: Task | None = None
class ats_linter.async_ast_parser.AsyncASTParser(file_paths: list[~pathlib.Path], test_modules: list[~ats_linter.data_classes.TestModule] = <factory>)[source]

Bases: object

Parse Python files into TestModule objects.

This class encapsulates the logic of parsing Python files into TestModule objects. It is used in conjunction with ASTProducer and ASTConsumer.

Parameters:
  • file_paths (The paths of the Python files to parse.)

  • test_modules (The list of TestModule objects produced from the Python files.)

async async_run()[source]

Run the producer-consumer task in an async context.

file_paths: list[Path]
async classmethod from_files(file_paths)[source]

Async factory for use in async test environments.

async gather_producer_consumer_task()[source]

Gather the producer-consumer task.

run()[source]

Run the producer-consumer task, compatible with sync and async contexts.

async run_producer_consumer()[source]

Run the producer-consumer pattern.

test_modules: list[TestModule]

6.1.4. ats_linter.cli module

Copyright (c) 2023 Aydin Abdi.

CLI for the Automated Test Schema Linter (ATS Linter). Modern, typed, and Pythonic using Typer.

ats_linter.cli.main(files: ~typing.Annotated[list[str], <typer.models.ArgumentInfo object at 0x78f0250895d0>] = None, debug: ~typing.Annotated[bool, <typer.models.OptionInfo object at 0x78f022fbae50>] = False) None[source]

Lint test files for docstring compliance.

Parameters:
  • files – Files or directories to lint (default: tests/ directory)

  • debug – Enable debug logging

ats_linter.cli.run() None[source]

Entry point for the CLI.

6.1.5. ats_linter.data_classes module

Copyright (c) 2023 Aydin Abdi.

This module defines the data classes used in this module.

class ats_linter.data_classes.Entity(name: str, docstring: str | None, code: str)[source]

Bases: object

Represent a generic entity in a test module.

Parameters:
  • name (The name of the entity.)

  • docstring (The docstring of the entity.)

  • code (The code of the entity.)

code: str
docstring: str | None
name: str
class ats_linter.data_classes.PytestFixture(name: str, docstring: str | None, code: str)[source]

Bases: object

Represent a pytest fixture.

Parameters:
  • name (The name of the fixture.)

  • docstring (The docstring of the fixture.)

  • code (The code of the fixture.)

code: str
docstring: str | None
name: str
class ats_linter.data_classes.Section(name: str, error_message: str | None)[source]

Bases: object

Represent a section in a test description for MHSTestLinter.

Parameters:
  • name (The name of the section.)

  • error_message (The error message of the section.)

error_message: str | None
name: str
class ats_linter.data_classes.TestCase(name: str, docstring: str, code: str)[source]

Bases: object

Represent a test case.

Parameters:
  • name (The name of the test case.)

  • docstring (The docstring of the test case.)

  • code (The code of the test case.)

code: str
docstring: str
name: str
class ats_linter.data_classes.TestClass(name: str, docstring: str | None, test_cases: list[TestCase], fixtures: list[PytestFixture])[source]

Bases: object

Represent a test class.

Parameters:
  • name (The name of the test class.)

  • docstring (The docstring of the test class.)

  • test_cases (The list of test cases in the class.)

  • fixtures (The list of fixtures in the class.)

docstring: str | None
fixtures: list[PytestFixture]
name: str
test_cases: list[TestCase]
class ats_linter.data_classes.TestModule(name: str, test_classes: list[TestClass], test_cases: list[TestCase], fixtures: list[PytestFixture])[source]

Bases: object

Represent a test module.

Parameters:
  • name (The name of the module.)

  • test_classes (The list of test classes in the module.)

  • test_cases (The list of test cases in the module.)

  • fixtures (The list of fixtures in the module.)

fixtures: list[PytestFixture]
name: str
test_cases: list[TestCase]
test_classes: list[TestClass]

6.1.6. ats_linter.description module

Copyright (c) 2023 Aydin Abdi.

This module encapsulates the logic of parsing test case test descriptions.

class ats_linter.description.TestDescription(docstring: str, objective: str | None = None, approvals: list[str] = <factory>, preconditions: dict[int, str] | None=<factory>, data_driven_test: list[str] | None = <factory>, test_steps: dict[int, str]=<factory>, verify_steps: dict[int, str]=<factory>)[source]

Bases: object

Represents a test case test description.

Parameters:
  • objective (The objective of the test.)

  • approvals (The approval criteria of the test.)

  • preconditions (The preconditions of the test. None if not provided.)

  • data_driven_test (The data-driven test descriptions. None if not provided.)

  • test_steps (The steps to execute the test.)

  • verify_steps (The steps that verifies test.)

approvals: list[str]
data_driven_test: list[str] | None
docstring: str
objective: str | None = None
preconditions: dict[int, str] | None
test_steps: dict[int, str]
verify_steps: dict[int, str]
class ats_linter.description.TestDescriptionFactory[source]

Bases: object

Create a TestDescription instance from various sources.

static dataclass_test_docstring_factory(docstring: str) TestDescription[source]

Create a TestDescription instance from a docstring.

Parameters:

docstring – The docstring to parse.

Returns:

class: TestDescription instance.

static from_docstring(docstring: str) TestDescription[source]

Create a TestDescription from a docstring (compatibility alias).

static parse_dash_list_section(section: str) list[str][source]

Parse dash(start with ‘-’) list sections from the docstring.

Parameters:

section – The section string to parse.

Returns:

A list of items parsed from the section.

static parse_numbered_list_section(section: str) dict[int, str][source]

Parse numbered(1. 2. 3.) list sections from the docstring.

Parameters:

section – The section string to parse.

Returns:

A dictionary with list order as key and item as value.

static parse_verify_steps(test_steps: dict[int, str]) dict[int, str][source]

Parse verify steps from the test steps.

Parameters:

test_steps – The test steps to parse.

Returns:

A dictionary with key of test steps as key and verify step value as value.

6.1.7. ats_linter.exception module

Copyright (c) 2023 Aydin Abdi.

This module defines the base class for exceptions in this module.

Example

raise ATSLinterError(“This is an error message.”)

exception ats_linter.exception.ATSASTParseError(message: str)[source]

Bases: ATSLinterError

Exception raised for errors in AST parsing.

exception ats_linter.exception.ATSFileCollectionError(message: str)[source]

Bases: ATSLinterError

Exception raised for errors in file collection.

exception ats_linter.exception.ATSLinterError(message: str)[source]

Bases: Exception

Base class for exceptions in this module.

Parameters:

message (The error message.)

6.1.8. ats_linter.file_collector module

Copyright (c) 2023 Aydin Abdi.

This module defines a class for collecting test directories and files.

Example

test_directory = FileCollector(‘/path/to/root/directory’) print(test_directory.test_directories) print(test_directory.test_files)

class ats_linter.file_collector.FileCollector(root_file_path: dataclasses.InitVar[str])[source]

Bases: object

Collect test directories and files from a root directory or file.

Parameters:
  • root_file_path (The path of the root directory or file.)

  • root_path (The root directory as a Path object.)

  • test_directories (A list of all directories that contain test files.)

  • test_files (A list of all test files.)

Example

test_directory = FileCollector(‘/path/to/root/directory’) print(test_directory.test_directories) print(test_directory.test_files)

collect_test_directories_and_files_in_parallel() None[source]

Collect all test directories and files in parallel.

If the root directory is a file, simply add it to the test files and return. If the root directory is a directory, collect all test directories and files.

static get_path_from_string(file_path: str) Path[source]

Return a Path object for a given file path string.

Parameters:

file_path – The file path as a string.

Returns:

The file path as a Path object.

static is_test_directory(directory: Path) bool[source]

Check if the directory is a test directory.

A directory is considered a test directory if it starts with test or test_ or tests and contains at least one file that starts with test_.

Parameters:

directory – The directory to check.

Returns:

True if the directory is a test directory, False otherwise.

static is_test_file(file: Path) bool[source]

Check if the file is a test file.

Parameters:

file – The file to check.

Returns:

True if the file is a test file, False otherwise.

static process_directory(directory: Path) tuple[Path | None, list[Path]][source]

Process a directory and return it if it is a test directory.

Parameters:

directory – The directory to process.

Returns:

A tuple containing the directory and its test files.

root_file_path: dataclasses.InitVar[str]
root_path: Path
test_directories: list[Path]
test_files: list[Path]

6.1.9. ats_linter.linter module

Copyright (c) 2023 Aydin Abdi.

Module to lint test files.

This module provides a class to lint test files.

class ats_linter.linter.ATSTestCase(test_case: TestCase)[source]

Bases: object

Represents a ATS test case.

Parameters:
  • test_case (The test case.)

  • test_description (ATS test case description :class: TestDescription.)

test_case: TestCase
test_description: TestDescription = None
class ats_linter.linter.ATSTestCasesFactory(test_cases: list[TestCase])[source]

Bases: object

Factory class to create :class: ATSTestCase objects.

Parameters:
  • test_cases (The list of :class: TestCase objects.)

  • ats_test_cases (The list of :class: ATSTestCase objects.)

ats_test_cases: list[ATSTestCase]
test_cases: list[TestCase]
class ats_linter.linter.ATSTestCasesLinter(ats_test_cases: list[ATSTestCase])[source]

Bases: object

Class to lint multiple ATS test cases.

Parameters:
  • ats_test_cases (The list of ATS test cases to lint.)

  • Example – (Doctest temporarily disabled due to API complexity) # >>> from ats_linter.data_classes import TestCase # >>> from ats_linter.linter import ATSTestCasesFactory, ATSTestCasesLinter # >>> test_case_1 = TestCase( # … name=”Test case name 1”, # … docstring=”Test case description 1”, # … code=”def test_something_1(): pass”, # … ) # >>> test_case_2 = TestCase( # … name=”Test case name 2”, # … docstring=”Test case description 2”, # … code=”def test_something_2(): pass”, # … ) # >>> factory = ATSTestCasesFactory([test_case_1, test_case_2]) # >>> ats_test_cases_linter = ATSTestCasesLinter(factory.ats_test_cases) # >>> ats_test_cases_linter.lint()

ats_test_cases: list[ATSTestCase]
lint() bool[source]

Lint the test case docstring and return the linting result.

Returns:

True if the test case docstring passes linting, False otherwise.

lint_results: dict[str, Any]
class ats_linter.linter.LintResult(module_name: str, class_name: str, test_name: str, sections: list[Section], result: bool)[source]

Bases: object

Class to represent the result of linting a test case.

class_name: str
module_name: str
result: bool
sections: list[Section]
test_name: str
class ats_linter.linter.LintTestCase(ats_test_case: ATSTestCase)[source]

Bases: object

Class to lint ATS test cases.

Parameters:
  • ats_test_case (The ATS test case :class: ATSTestCase.)

  • test_case (The test case :class: TestCase to lint.)

  • test_description (The ATS test case description :class: TestDescription.)

  • sections (The list of sections in the test case.)

  • Example – (Doctest temporarily disabled due to API complexity) # >>> from ats_linter.data_classes import TestCase # >>> from ats_linter.linter import ATSTestCase, LintTestCase # >>> test_case = TestCase( # … name=”Test case name”, # … docstring=”Test case description”, # … code=”def test_something(): pass”, # … ) # >>> ats_test_case = ATSTestCase(test_case) # >>> test_case_linter = LintTestCase(ats_test_case) # >>> test_case_linter.lint() # >>> test_case_linter.sections

ats_test_case: ATSTestCase
lint() bool[source]

Lint the test case docstring and return the linting result.

Returns:

True if the test case docstring passes linting, False otherwise.

lint_result: LintResult
sections: list[Section]
test_case: TestCase
test_description: TestDescription
ats_linter.linter.lint_ats_test_case(ats_test_case: ATSTestCase, lint_results: dict[str, Any], lock: allocate_lock) bool[source]

Lint a single test case.

Parameters:
  • ats_test_case – The ATS test case to lint.

  • lint_results – The dictionary to store linting results.

  • lock – The lock to ensure thread-safe access to the results dictionary.

Returns:

True if the test case passes linting, False otherwise.

6.1.10. ats_linter.parallel_process module

Copyright (c) 2023 Aydin Abdi.

FileProcessorCocurrent is a class for processing files in parallel.

class ats_linter.parallel_process.FileProcessorCocurrent(root_path: str)[source]

Bases: object

A class for processing files in parallel.

async_ast_parser: AsyncASTParser
root_path: str
test_file_collector: FileCollector

6.1.11. Module contents

Copyright (c) 2023 Aydin Abdi

Ats-linter(Automated Test Schema Linter) is a package for linting test files. It is a tool that checks the validity of test case docstrings and test code based on the defined schema. It is designed to be used in a CI/CD pipeline to ensure that test cases are written according to the defined schema. It is also designed to be used as a standalone tool to lint test files locally. It is built on top of Python’s AST (Abstract Syntax Tree). It can be used as a pre-commit hook.

Example

To lint test files locally, run the following command:

$ ats-linter --path tests/

To lint test files in a CI/CD pipeline, run the following command:

$ ats-linter --path tests/ --output junit.xml

The junit.xml file can be used to generate a report in Jenkins.

To lint test files in a CI/CD pipeline, run the following command:

$ ats-linter --path tests/ --output junit.xml

The junit.xml file can be used to generate a report in Jenkins.