hammurabi package

Submodules

hammurabi.config module

class hammurabi.config.CommonSettings(_env_file: Optional[Union[pathlib.Path, str]] = '<object object>', _env_file_encoding: Optional[str] = None, *, allow_push: bool = True, dry_run: bool = False, rule_can_abort: bool = False, git_branch_name: str = 'hammurabi', git_base_name: str = 'master', repository: str = '', report_name: pathlib.Path = PosixPath('hammurabi_report.json'))[source]

Bases: pydantic.env_settings.BaseSettings

Common settings which applies to both TOML and CLI configuration of Hammurabi.

Pillar configuration is intentionally not listed since it is represented as a string in the TOML configuration, but used the parsed variable in the CLI configuration.

class Config[source]

Bases: object

BaseSettings’ config describing how the settings will be handled. The given env_prefix will make sure that settings can be read from environment variables starting with HAMMURABI_.

env_prefix = 'hammurabi_'
allow_push: bool
dry_run: bool
git_base_name: str
git_branch_name: str
report_name: pathlib.Path
repository: str
rule_can_abort: bool
class hammurabi.config.Config[source]

Bases: object

Simple configuration object which used across Hammurabi. The Config loads the given pyproject.toml according to PEP-518.

Warning

When trying to use GitHub based laws without an initialized GitHub client (or invalid token), a warning will be thrown at the beginning of the execution. In case a PR open is attempted, a RuntimeError will be raised

load()[source]

Handle configuration loading from project toml file and make sure the configuration are initialized and merged. Also, make sure that logging is set properly. Before loading the configuration, it is a requirement to set the HAMMURABI_SETTINGS_PATH as it will contain the path to the toml file what Hammurabi expects. This is needed for cases when the 3rd party rules would like to read the configuration of Hammurabi.

… note:

The HAMMURABI_SETTINGS_PATH environment variable is set by the CLI by default, so there is no need to set if no 3rd party rules are used or those rules are not loading config.

Raises

Runtime error if HAMMURABI_SETTINGS_PATH environment variable is not set or an invalid git repository was given.

class hammurabi.config.Settings(_env_file: Optional[Union[pathlib.Path, str]] = '<object object>', _env_file_encoding: Optional[str] = None, *, allow_push: bool = True, dry_run: bool = False, rule_can_abort: bool = False, git_branch_name: str = 'hammurabi', git_base_name: str = 'master', repository: str = '', report_name: pathlib.Path = PosixPath('hammurabi_report.json'), pillar: object = None)[source]

Bases: hammurabi.config.CommonSettings

CLI related settings which are directly needed for the execution.

pillar: object
class hammurabi.config.TOMLSettings(_env_file: Optional[Union[pathlib.Path, str]] = '<object object>', _env_file_encoding: Optional[str] = None, *, allow_push: bool = True, dry_run: bool = False, rule_can_abort: bool = False, git_branch_name: str = 'hammurabi', git_base_name: str = 'master', repository: str = '', report_name: pathlib.Path = PosixPath('hammurabi_report.json'), github_token: str = '', log_level: str = 'INFO', log_path: pathlib.Path = PosixPath('hammurabi.log'), log_format: str = '%(levelname)s:%(name)s:%(message)s', pillar_config: pathlib.Path = PosixPath('pillar.conf.py'), pillar_name: str = 'pillar')[source]

Bases: hammurabi.config.CommonSettings

TOML Project configuration settings. Most of the fields are used to compose other configuration fields like github_token or pillar.

github_token: str
log_format: str
log_level: str
log_path: Optional[pathlib.Path]
pillar_config: pathlib.Path
pillar_name: str

hammurabi.exceptions module

exception hammurabi.exceptions.AbortLawError[source]

Bases: Exception

Custom exception to make sure that own exception types are caught by the Law’s execution.

exception hammurabi.exceptions.NotificationSendError[source]

Bases: Exception

Custom exception to make sure that own exception types are caught when sending notifications.

exception hammurabi.exceptions.PreconditionFailedError[source]

Bases: Exception

Custom exception representing a failed precondition. In case a precondition failed, there is no need to raise an error and report the rule as a failure. The precondition is for checking that a rule should or shouldn’t run; not for breaking the execution.

hammurabi.helpers module

hammurabi.helpers.full_strip(value: str) → str[source]

Strip every line.

hammurabi.law module

This module contains the definition of Law which is responsible for the execution of its registered Rules. Every Law can have multiple rules to execute.

In case a rule raises an exception the execution may abort and none of the remaining rules will be executed neither pipes or children. An abort can cause an inconsistent state or a dirty git branch. If rule_can_abort config is set to True, the whole execution of the :class:hammurabi.pillar.Pillar will be aborted and the original exception will be re-raised.

class hammurabi.law.Law(name: str, description: str, rules: Iterable[hammurabi.rules.base.Rule], preconditions: Iterable[hammurabi.preconditions.base.Precondition] = ())[source]

Bases: hammurabi.mixins.GitMixin

A Law is a collection of Rules which is responsible for the rule execution and git committing.

Example usage:

>>> from pathlib import Path
>>> from hammurabi import Law, Pillar, FileExists
>>>
>>> example_law = Law(
>>>     name="Name of the law",
>>>     description="Well detailed description what this law does.",
>>>     rules=(
>>>         FileExists(
>>>             name="Create pyproject.toml",
>>>             path=Path("./pyproject.toml")
>>>         ),
>>>     )
>>> )
>>>
>>> pillar = Pillar()
>>> pillar.register(example_law)
property can_proceed

Evaluate if the execution can be continued. If preconditions are set, those will be evaluated by this method.

Returns

Return with the result of evaluation

Return type

bool

Warning

hammurabi.rules.base.Rule.can_proceed() checks the result of self.preconditions, which means the preconditions are executed. Make sure that you are not doing any modifications within rules used as preconditions, otherwise take extra attention for those rules.

commit() → None[source]

Commit the changes made by registered rules and add a meaningful commit message.

Example commit message:

Migrate to next generation project template
* Create pyproject.toml
* Add meta info from setup.py to pyproject.toml
* Add existing dependencies
* Remove requirements.txt
* Remove setup.py
property documentation

Get the name and description of the Law object.

Returns

Return the name and description of the law as its documentation

Return type

str

enforce() → None[source]

Execute all registered rule. If rule_can_abort config option is set to True, all the rules will be aborted and an exception will be raised.

When the whole execution chain is finished, the changes will be committed except the failed ones.

Note

Failed rules and their chain (excluding prerequisites) will be added to the pull request description.

Raises

AbortLawError

property failed_rules

Return the rules which did modifications and failed.

Returns

Return the failed rules

Return type

Union[Tuple[()], Tuple[Rule]]

get_execution_order() → List[Union[hammurabi.rules.base.Rule, hammurabi.preconditions.base.Precondition]][source]

Get the execution order of the registered rules. The order will contain the pipes and children as well.

This helper function is useful in debugging and information gathering.

Returns

Return the execution order of the rules

Return type

List[Rule]

property passed_rules

Return the rules which did modifications and not failed.

Returns

Return the passed rules

Return type

Tuple[Rule, ..]

property skipped_rules

Return the rules which neither modified the code nor failed.

Returns

Return the skipped rules

Return type

Tuple[Rule, ..]

hammurabi.main module

class hammurabi.main.LoggingChoices(value)[source]

Bases: str, enum.Enum

Logging choices for CLI settings.

DEBUG = 'DEBUG'
ERROR = 'ERROR'
INFO = 'INFO'
WARNING = 'WARNING'
hammurabi.main.enforce(ctx: typer.models.Context, dry_run: bool = <typer.models.OptionInfo object>, allow_push: bool = <typer.models.OptionInfo object>, report: bool = <typer.models.OptionInfo object>)[source]

The enforce command executes the laws registered on the pillar. But the command has other responsibilities too. It will make sure the execution report is generated and controls if the changes are pushed to remote or not.

hammurabi.main.error_message(message: str, should_exit: bool = True, code: int = 1)[source]

Print error message and exit the CLI application

hammurabi.main.main(ctx: typer.models.Context, cfg: pathlib.Path = <typer.models.OptionInfo object>, repository: str = <typer.models.OptionInfo object>, token: str = <typer.models.OptionInfo object>, log_level: hammurabi.main.LoggingChoices = <typer.models.OptionInfo object>)[source]

Hammurabi is an extensible CLI tool responsible for enforcing user-defined rules on a git repository.

Find more information at: https://hammurabi.readthedocs.io/latest/

hammurabi.main.print_message(message: str, color: str, bold: bool, should_exit: bool, code: int)[source]

Print formatted message and exit if requested.

hammurabi.main.success_message(message: str)[source]

Print error message and exit the CLI application

hammurabi.main.version()[source]

Print hammurabi version.

hammurabi.mixins module

Mixins module contains helpers for both laws and rules. Usually this file will contain Git commands related helpers. Also, this module contains the extensions for several online git based VCS.

class hammurabi.mixins.GitHubMixin[source]

Bases: hammurabi.mixins.GitMixin, hammurabi.mixins.PullRequestHelperMixin

Extending hammurabi.mixins.GitMixin to be able to open pull requests on GitHub after changes are pushed to remote.

create_pull_request() → Optional[str][source]

Create a PR on GitHub after the changes are pushed to remote. The pull request details (repository, branch) are set by the project configuration. The mapping of the details and configs:

Detail

Configuration

repo

repository (owner/repository format)

base

git_base_name

branch

git_branch_name

Returns

Return the open (and updated) or opened PR’s url

Return type

Optional[str]

class hammurabi.mixins.GitMixin[source]

Bases: object

Simple mixin which contains all the common git commands which are needed to push a change to an online VCS like GitHub or GitLab. This mixin could be used by hammurabi.law.Law`s, :class:`hammurabi.rules.base or any rules which can make modifications during its execution.

static checkout_branch() → None[source]

Perform a simple git checkout, to not pollute the default branch and use that branch for the pull request later. The branch name can be changed in the config by setting the git_branch_name config option.

The following command is executed:

git checkout -b <branch name>
git_add(param: pathlib.Path) → None[source]

Add file contents to the index.

Parameters

param (Path) – Path to add to the index

The following command is executed:

git add <path>
git_commit(message: str) → None[source]

Commit the changes on the checked out branch.

Parameters

message (str) – Git commit message

The following command is executed:

git commit -m "<commit message>"
static git_diff(**kwargs) → List[str][source]

Get the diff of files.

Returns

Returns the git diff command and its output

Return type

bool

The following command is executed

git diff [options]
git_remove(param: pathlib.Path) → None[source]

Remove files from the working tree and from the index.

Parameters

param (Path) – Path to remove from the working tree and the index

The following command is executed:

git rm <path>
static push_changes() → bool[source]

Push the changes with the given branch set by git_branch_name config option to the remote origin.

The following command is executed:

git push origin <branch name>
Returns

Return whether the changes are pushed

Return type

bool

class hammurabi.mixins.PullRequestHelperMixin[source]

Bases: object

Give helper classes for pull request related operations

generate_pull_request_body(pillar) → str[source]

Generate the body of the pull request based on the registered laws and rules. The pull request body is markdown formatted.

Parameters

pillar (hammurabi.pillar.Pillar) – Pillar configuration

Returns

Returns the generated pull request description

Return type

str

hammurabi.pillar module

Pillar module is responsible for handling the whole execution chain including executing the registered laws, pushing the changes to the VCS and creating a pull request. All the laws registered to the pillar will be executed in the order of the registration.

class hammurabi.pillar.Pillar(reporter_class: Type[hammurabi.reporters.base.Reporter] = <class 'hammurabi.reporters.json.JsonReporter'>, notifications: Iterable[hammurabi.notifications.base.Notification] = ())[source]

Bases: hammurabi.mixins.GitHubMixin

Pillar is responsible for the execution of the chain of laws and rules.

All the registered laws and rules can be retrieved using the laws and rules properties, or if necessary single laws and rules can be accessed using the resource’s name as a parameter for get_law or get_rule methods.

As a final step, pillar will prepare its reporter for report generation. For more information about reporters, check hammurabi.reporters.base.Reporter and hammurabi.reporters.json.JsonReporter.

Parameters

reporter_class (Type[Reporter]) – The reporter class used for generating the reports

enforce()[source]

Run all the registered laws and rules one by one. This method is responsible for executing the registered laws, push changes to the git origin and open the pull request.

This method glues together the lower level components and makes sure that the execution of laws and rules can not be called more than once at the same time for a match.

get_law(name: str)hammurabi.law.Law[source]

Get a law by its name. In case of no Laws are registered or the law can not be found by its name, a StopIteration exception will be raised.

Parameters

name (str) – Name of the law which will be used for the lookup

Raises

StopIteration exception if Law not found

Returns

Return the searched law

Return type

hammurabi.law.Law

get_rule(name: str)hammurabi.rules.base.Rule[source]

Get a registered rule (and its pipe/children) by the rule’s name.

This helper function is useful in debugging and information gathering.

Parameters

name (str) – Name of the rule which will be used for the lookup

Raises

StopIteration exception if Rule not found

Returns

Return the rule in case of a match for the name

Return type

Rule

property laws

Return the registered laws in order of the registration.

register(law: hammurabi.law.Law)[source]

Register the given Law to the Pillar. The order of the registration does not matter. The laws should never depend on each other.

Parameters

law (hammurabi.law.Law) – Initialized Law which should be registered

Example usage:

>>> from pathlib import Path
>>> from hammurabi import Law, Pillar, FileExists
>>>
>>> example_law = Law(
>>>     name="Name of the law",
>>>     description="Well detailed description what this law does.",
>>>     rules=(
>>>         FileExists(
>>>             name="Create pyproject.toml",
>>>             path=Path("./pyproject.toml")
>>>         ),
>>>     )
>>> )
>>>
>>> pillar = Pillar()
>>> pillar.register(example_law)

Warning

The laws should never depend on each other, because the execution may not happen in the same order the laws were registered. Instead, organize the depending rules in one law to resolve any dependency conflicts.

property rules

Return all the registered laws’ rules.

Module contents