labelord package

Submodules

labelord.cli module

CLI module

This module contains application’s entry point and command line interface logic.

labelord.cli.main()[source]

Application’s entry point.

Runs the application and passes control to the command line interface.

labelord.constants module

Constants module

This module contains constants shared between other modules.

labelord.constants.DEFAULT_CONFIG_FILE

str – Path to configuration file.

labelord.constants.DEFAULT_SUCCESS_RETURN

int – Default return code for success.

labelord.constants.DEFAULT_ERROR_RETURN

int – Default return code for error.

labelord.constants.NO_GH_TOKEN_RETURN

int – Default return code for when GitHub token is not specified.

labelord.constants.GH_ERROR_RETURN

dict – Default return codes for when GitHub returns an error.

labelord.constants.NO_LABELS_SPEC_RETURN

int – Default return code for when no labels are specified.

labelord.constants.NO_REPOS_SPEC_RETURN

int – Default return code for when no GitHub repositories are specified.

labelord.constants.NO_WEBHOOK_SECRET_RETURN

int – Default return code for when there is no webhook secret specified.

labelord.github module

GitHub module

This module contains classes and methods for working and communicating with GitHub API (including error handling).

class labelord.github.GitHub(token, session=None)[source]

Bases: object

GitHub API class.

This class contains methods for communicating with GitHub API. Initializing an instance will set its token and session.

Example

import requests
import labelord
github = labelord.github.GitHub('123456')
>>> github.token
'123456'
req = requests.Request()
github.session.auth(req)
>>> req.headers['Authorization']
'token 123456'
>>> req.headers['User-Agent']
'Python/Labelord'
Parameters:
GH_API_ENDPOINT = 'https://api.github.com'

str – URL of GitHub API endpoint.

create_label(repository, name, color, **kwargs)[source]

Creates new label in given repository

This method creates new label with specified name and color in given repository.

Parameters:
  • repository (str) – GitHub repository slug (eg. User/Repo).
  • name (str) – New label’s name.
  • color (str) – New label’s color.
  • kwargs (dict) – Other arguments placeholder, not used.
Raises:

GitHubError – If status code returned by GitHub is not 201.

delete_label(repository, name, **kwargs)[source]

Deletes existing label in given repository

This method deletes existing label from given repository.

Parameters:
  • repository (str) – GitHub repository slug (eg. User/Repo).
  • name (str) – Deleted label’s name.
  • kwargs (dict) – Other arguments placeholder, not used.
Raises:

GitHubError – If status code returned by GitHub is not 204.

list_labels(repository)[source]

Gets dict of labels with colors for given repository slug

This method gets labels with colors for given GitHub repository.

Parameters:repository (str) – GitHub repository slug (eg. User/Repo).
Returns:Color for each label in repository.
Return type:dict
list_repositories()[source]

Gets a list of names of accessible repositories (including owner)

This method gets a list of names of GitHub repositiories accessible with given GitHub API token.

Returns:List of repository names (full, eg. User/Repo).
Return type:list
set_session(session)[source]

Sets session

This method sets new session including headers for use within class.

Parameters:session (requests.Session) – Session to use.
update_label(repository, name, color, old_name=None, **kwargs)[source]

Updates existing label in given repository

This method updates given repository’s existing label’s name and color.

Parameters:
  • repository (str) – GitHub repository slug (eg. User/Repo).
  • name (str) – Updated label’s new name.
  • color (str) – Updated label’s new color.
  • old_name (Optional[str]) – Updated label’s old name, default: None.
  • kwargs (dict) – Other arguments placeholder, not used.
Raises:

GitHubError – If status code returned by GitHub is not 200.

static webhook_verify_signature(data, signature, secret, encoding='utf-8')[source]

Verifies webhook signature

This method verifies webhook signature.

Example

import hashlib
import hmac
import labelord

github = labelord.github.GitHub('123456')
data = 'test data'.encode('utf-8')
secret = 'secret'
signature  = 'sha1=a81d790e8312e98f84aacaf95ca9dd04e5305fbf'
>>> github.webhook_verify_signature(data, signature, secret)
True
data = 'other data'.encode('utf-8')
>>> github.webhook_verify_signature(data, signature, secret)
False
Parameters:
  • data (str) – Incoming request data.
  • signature (str) – GitHub signature.
  • secret (str) – Webhook secret.
  • encoding (Optional[str]) – Character encoding used for secret, default: utf-8.
Returns:

Webhook signature verification result.

Return type:

bool

exception labelord.github.GitHubError(response)[source]

Bases: Exception

GitHub error class.

This class contains methods describing and used for working with errors returned by GitHub. Initializing an instance will parse status code and message from GitHub response.

Example

import requests
import labelord

res = requests.Response()
res.status_code = 400
res.json = lambda: {}
gh_error = labelord.github.GitHubError(res)
>>> gh_error.status_code
400

>>> gh_error.message
'No message provided'
Parameters:response (requests.Response) – GitHub response.
code_message

Formats an error.

This method returns formatted GitHub error.

Example

import requests
import labelord

res = requests.Response()
res.status_code = 400
res.json = lambda: {}
gh_error = labelord.github.GitHubError(res)
>>> gh_error.code_message
'400 - No message provided'
Parameters:sep (Optional[str]) – Separator, default: ‘ - ‘.
Returns:GitHub error in the format of code sep message.
Return type:str

labelord.helpers module

Helpers module

This module contains helper functions for use by other modules.

labelord.helpers.create_config(config_filename=None, token=None)[source]

Creates configuration object

This function parses configuration file and GitHub API token into configuration object.

Example

import configparser
import labelord

cfg = labelord.helpers.create_config('../config.example.cfg', '123456')
>>> cfg['github']['token']
'123456'

>>> cfg['github']['webhook_secret']
'MY_WEBHOOK_SECRET'

>>> cfg['labels']['Bug']
'FF0000'

>>> cfg['others']['template-repo']
'MarekSuchanek/myLabels'

>>> cfg['repos']['MarekSuchanek/repo1']
'on'

>>> cfg['repos']['CVUT/MI-PYT']
'off'
Parameters:
  • config_filename (Optional[str]) – Path to configuration file, default: None.
  • token (Optional[str]) – GitHub API token, default: None.
Returns:

Parsed configuration object.

Return type:

configparser.ConfigParser

labelord.helpers.extract_labels(gh, template_opt, cfg)[source]

Extracts GitHub labels from various locations

This function lists labels from specified GitHub repository, from template repository specified in configuration file, or from ‘labels’ section in the configuration file.

Example

import labelord

gh = labelord.github.GitHub('123456')
cfg = labelord.helpers.create_config('../config.example.cfg', '123456')
cfg.pop('others', None)

labels = labelord.helpers.extract_labels(gh, None, cfg)
>>> labels['Idea']
'23FB89'
Parameters:
  • gh (GitHub) – GitHub class instance.
  • template_opt (str) – Template repository to get list of labels from.
  • cfg (configparser.ConfigParser) – Parsed configuration object.
Returns:

Color for each extracted label.

Return type:

dict

labelord.helpers.extract_repos(cfg)[source]

Extracts GitHub repositories from configuration

This function extracts list of GitHub repositories from parsed configuration object.

Example

import labelord

cfg = labelord.helpers.create_config('../config.example.cfg', '123456')
repos = labelord.helpers.extract_repos(cfg)
>>> 'MarekSuchanek/repo1' in repos
True

>>> 'CVUT/MI-PYT' in repos
False

>>> 'MarekSuchanek/repo3' in repos
False
Parameters:cfg (configparser.ConfigParser) – Parsed configuration object.
Returns:List of repositories.
Return type:list
labelord.helpers.gh_error_return(github_error)[source]

Gets return code based on a GitHub error

This function returns appropriate return code for a status code returned by GitHub API.

Example

import requests
import labelord

res = requests.Response()
res.status_code = 401
res.json = lambda: {}

gh_error = labelord.github.GitHubError(res)
>>> labelord.helpers.gh_error_return(gh_error)
4
gh_error.status_code = 404
>>> labelord.helpers.gh_error_return(gh_error)
5
Parameters:github_error (GitHubError) – Error returned by GitHub API.
Returns:Return code.
Return type:int
labelord.helpers.pick_printer(verbose, quiet)[source]

Returns specified printer

This function returns a Printer based on specified parameters.

Parameters:
  • verbose (bool) – Whether to return a VerbosePrinter.
  • quiet (bool) – Whether to return a QuietPrinter.
Returns:

Instance of a Printer (Printer, QuietPrinter or VerbosePrinter).

Return type:

Printer

labelord.helpers.pick_runner(dry_run)[source]

Returns specified processor

This function returns a Processor based on specified parameters.

Parameters:dry_run (bool) – Whether to return a DryRunProcessor.
Returns:Instance of a Processor (RunProcessor or DryRunProcessor).
Return type:Printer
labelord.helpers.retrieve_github_client(ctx)[source]

Retrieves GitHub class instance

This function gets GitHub class instance from configuration for communitation with GitHub API.

Parameters:ctx (click.Context) – Click context object.
Returns:GitHub class instance
Return type:GitHub

labelord.printers module

Printers module

This module contains BasePrinter class and its descendants. They serve to print information so user is notified about application’s performed actions.

class labelord.printers.BasePrinter[source]

Bases: object

Basic printer interface

This class serves as an ancestor to other printer classes within this module and defines their common interface. Initializing an instance will initialize an empty set of the printer’s registered GitHub repositories and sets error count to zero.

Example

import labelord
printer = labelord.printers.BasePrinter()
>>> type(printer.repos)
<class 'set'>

>>> len(printer.repos)
0

>>> printer.errors
0
ERROR_SUMMARY = '{} error(s) in total, please check log above'

str – Summarizing message in case of error.

EVENT_CREATE = 'ADD'

str – Output tag for create event (new label is created).

EVENT_DELETE = 'DEL'

str – Output tag for delete event (label is deleted).

EVENT_LABELS = 'LBL'

str – Output tag for read labels event (labels are read from repository, shows only if an error occurs in this phase).

EVENT_UPDATE = 'UPD'

str – Output tag for update event (label is updated).

RESULT_DRY = 'DRY'

str – Output tag for successfully simulated operation.

RESULT_ERROR = 'ERR'

str – Output tag for unsuccessfully performed operation.

RESULT_SUCCESS = 'SUC'

str – Output tag for successfully performed operation.

SUCCESS_SUMMARY = '{} repo(s) updated successfully'

str – Summarizing message in case of success.

add_repo(slug)[source]

Registers repository for the printer

This method adds given repository to the printer’s set of registered repositories.

Example

import labelord

printer = labelord.printers.BasePrinter()
printer.add_repo('User/Repo')
>>> 'User/Repo' in printer.repos
True
Parameters:slug (str) – GitHub repository slug (eg. User/Repo).
event(event, result, repo, *args)[source]

Processes printer events

This method processes printer events and increments its error count in case of unsuccessfully performed operation.

Example

import labelord

printer = labelord.printers.BasePrinter()
printer.event('Test error event', 'ERR', 'User/Repo')
>>> printer.errors
1
Parameters:
  • event (str) – Event description.
  • result (str) – Event result.
  • repo (str) – Repository where event happened.
  • args (list) – Additional arguments (placeholder).
summary()[source]

Interface for printing summary

This method only passes control to the subclass.

class labelord.printers.Printer[source]

Bases: labelord.printers.BasePrinter

Default printer

This class describes default printer, which only prints errors and summary.

event(event, result, repo, *args)[source]

Processes printer events

This method processes printer events through base class’ method and prints any errors.

Example

import labelord
printer = labelord.printers.Printer()
>>> printer.event('ADD', 'ERR', 'User/Repo')
ERROR: ADD; User/Repo

>>> printer.errors
1
Parameters:
  • event (str) – Event description.
  • result (str) – Event result.
  • repo (str) – Repository where event happened.
  • args (list) – Additional arguments describing the error.
summary()[source]

Prints summary

This method prints summary after all operations are processed.

Example

import labelord
printer = labelord.printers.Printer()
>>> printer.summary()
SUMMARY: 0 repo(s) updated successfully
class labelord.printers.QuietPrinter[source]

Bases: labelord.printers.BasePrinter

Quiet printer

This class describes quiet printer, which prints nothing.

Example

import labelord
printer = labelord.printers.QuietPrinter()
>>> printer.event('ADD', 'SUC', 'User/Repo')
>>> printer.event('UPD', 'ERR', 'User/Repo')
>>> printer.summary()

>>> printer.errors
1
class labelord.printers.VerbosePrinter[source]

Bases: labelord.printers.BasePrinter

Verbose printer

This class describes verbose printer, which prints detailed information about every performed operation including its result. Also prints summary after all operations are processed.

LINE_START = '[{}][{}] {}'

str – Defines printed line format.

event(event, result, repo, *args)[source]

Processes printer events

This method processes printer events through base class’ method and prints detailed information about every event including its result.

Example

import labelord
printer = labelord.printers.VerbosePrinter()
>>> printer.event('ADD', 'ERR', 'User/Repo')
[ADD][ERR] User/Repo

>>> printer.event('UPD', 'SUC',  'User/Repo')
[UPD][SUC] User/Repo

>>> printer.errors
1
Parameters:
  • event (str) – Event description.
  • result (str) – Event result.
  • repo (str) – Repository where event happened.
  • args (list) – Additional arguments describing the event.
summary()[source]

Prints summary

This method prints summary after all operations are processed.

Example

import labelord
printer = labelord.printers.VerbosePrinter()
>>> printer.summary()
[SUMMARY] 0 repo(s) updated successfully

labelord.processors module

Processors module

This module contains classes which process application’s actions to update or replace labels within given GitHub repository. These describe both ‘live’ and dry run (simulation).

class labelord.processors.DryRunProcessor(github, printer=None)[source]

Bases: labelord.processors.RunProcessor

Application’s dry run

This class describes application’s dry run - it simulates an update or a replacement (based on specified mode) of labels in given GitHub repository. Initializing an instance will obtain GitHub and Printer class instances.

Parameters:
  • github (GitHub) – GitHub class instance.
  • printer (Optional[BasePrinter]) – Printer instance, default: None.
class labelord.processors.RunModes[source]

Bases: object

Application run modes

This class describes both updating and replacing labels.

classmethod replace_mode(labels, labels_specs)[source]

Application mode: Replace

Creates label if it doesn’t exist, updates if it does and removes any extra labels.

Example

import labelord

labels = { 'old': '000000', 'other': '222222' }
labels_specs = { 'new': '111111', 'old': 'FFFFFF' }
>>> labelord.processors.RunModes.replace_mode(labels, labels_specs)
({'new': ('new', '111111')}, {'old': ('old', 'FFFFFF')}, {'other': ('other', '222222')})
Parameters:
  • labels (dict) – Repository labels.
  • labels_specs (dict) – New labels specifications.
Returns:

Labels to create, update and delete.

Return type:

tuple(dict)

classmethod update_mode(labels, labels_specs)[source]

Application mode: Update

Creates label if it doesn’t exist, updates if it does and keeps any extra labels.

Example

import labelord

labels = { 'old': '000000', 'other': '222222' }
labels_specs = { 'new': '111111', 'old': 'FFFFFF' }
>>> labelord.processors.RunModes.update_mode(labels, labels_specs)
({'new': ('new', '111111')}, {'old': ('old', 'FFFFFF')}, {})
Parameters:
  • labels (dict) – Repository labels.
  • labels_specs (dict) – New labels specifications.
Returns:

Labels to create, update and delete.

Return type:

tuple(dict)

class labelord.processors.RunProcessor(github, printer=None)[source]

Bases: object

Application’s ‘live’ run

This class describes application’s ‘live’ run - it performs an update or a replacement (based on specified mode) of labels in given GitHub repository. Initializing an instance will obtain GitHub and Printer class instances.

Parameters:
  • github (GitHub) – GitHub class instance.
  • printer (Optional[BasePrinter]) – Printer instance, default: None.
MODES = {'update': <bound method RunModes.update_mode of <class 'labelord.processors.RunModes'>>, 'replace': <bound method RunModes.replace_mode of <class 'labelord.processors.RunModes'>>}

dict – Holds application run modes

run(slugs, labels_specs, mode)[source]

Performs application’s ‘live’ run

This method updates or replaces labels in given GitHub repositories and passes information about performed operations to a printer.

Parameters:
  • slugs (list) – List of GitHub repositories (in the format of User/Repo).
  • labels_specs (dict) – New labels specifications.
  • mode (types.FunctionType) – Application run mode (update or replace).
Returns:

Return code.

Return type:

int

labelord.web module

Web module

This module holds web application logic.

class labelord.web.LabelordChange(action, name, color, new_name=None)[source]

Bases: object

Labelord Change

This class describes one change within web application and provides method to check its validity. Initializing an instance will set its action, name, color and old_name. It will also set the timestamp to current time.

Example

import time
import labelord

change = labelord.web.LabelordChange('created', 'Bug', 'FF0000')
>>> change.action
'created'

>>> change.name
'Bug'

>>> change.color
'FF0000'

>>> change.old_name

>>> type(change.timestamp)
<class 'int'>
Parameters:
  • action (str) – Action performed (created, edited, deleted).
  • name (str) – Label name.
  • color (str) – Label color.
  • new_name (Optional[str]) – New label name, default: None.
CHANGE_TIMEOUT = 10

int – Timeout for a change.

is_valid()[source]

Tests change validity

This method checks whether given change is valid using timeout.

Example

import time
import labelord

change = labelord.web.LabelordChange('created', 'Bug', 'FF0000')
>>> change.is_valid()
True
Returns:Whether the change is valid.
Return type:bool
tuple

Formats change into a tuple

This method makes a representation of the change in the form of a tuple.

Example

import time
import labelord

change = labelord.web.LabelordChange('created', 'Bug', 'FF0000')
>>> change.tuple
('created', 'Bug', 'FF0000', None)
Returns:Labelord change (action, label name, label color, label new name).
Return type:tuple
class labelord.web.LabelordWeb(labelord_config, github, *args, **kwargs)[source]

Bases: flask.app.Flask

Labelord web application

This class holds web application logic. Initializing an instance will load application’s configuration, obtain GitHub class instance for communicating with GitHub API and initialize a dictionary of ignores (valid changes for given repository). It will also call the base class’ constructor passing any additional arguments.

Example

import labelord
app = labelord.web.LabelordWeb(None, None, import_name = '')
>>> app.ignores
{}
Parameters:
  • labelord_config (configparser.ConfigParser) – Parsed configuration object.
  • github (GitHub) – GitHub class instance.
  • args (list) – Additional arguments for base class.
  • kwargs (dict) – Additional keyword arguments for base class.
cleanup_ignores()[source]

Cleans up invalid changes

This method checks lists of changes for every GitHub repository and removes those changes which are not valid.

Example

import labelord

valid_change = labelord.web.LabelordChange('created', 'Bug', 'FF0000')
invalid_change = labelord.web.LabelordChange('deleted', 'Bug', 'FF0000')
invalid_change.timestamp -= 20

app = labelord.web.LabelordWeb(None, None, import_name = '')
app.ignores['User/Repo'] = [valid_change, invalid_change]

app.cleanup_ignores()
>>> len(app.ignores['User/Repo'])
1

>>> app.ignores['User/Repo'][0].action
'created'
static create_app(config=None, github=None)[source]

Creates web application

This method performs configuration loading including GitHub API token and creates labelord web application.

Example

import labelord
app = labelord.web.LabelordWeb.create_app()
>>> type(app)
<class 'labelord.web.LabelordWeb'>
Parameters:
  • config (configparser.ConfigParser) – Parsed configuration object.
  • github (GitHub) – GitHub class instance.
Returns:

labelord web application instance

Return type:

LabelordWeb

finish_setup()[source]

Finalizes application’s setup

This method checks application’s configuration and performs error handlers initialization.

inject_session(session)[source]

Sets new session for communitation with GitHub API

This method passes new session to the GitHub class instance.

Parameters:session (requests.Session) – Session to inject.
process_label_webhook(data)[source]

Processes user action on label

This method processes webhook and extracts change made by the user. Then it passes this change for further processing.

Parameters:data (dict) – Webhook data.
process_label_webhook_create(label, repo)[source]

Processes ‘created’ change

This method processes a create label action made by the user.

Parameters:
  • label (dict) – Created label’s name and color.
  • repo (str) – Repository to create label in.
process_label_webhook_delete(label, repo)[source]

Processes ‘deleted’ change

This method processes a remove label action made by the user.

Parameters:
  • label (dict) – Deleted label’s name and color.
  • repo (str) – Repository to delete label from.
process_label_webhook_edit(label, repo, changes)[source]

Processes ‘edited’ change

This method processes an update label action made by the user.

Parameters:
  • label (dict) – Updated label’s new name and color.
  • repo (str) – Repository to update label in.
  • changes (dict) – Contains updated label’s old name.
reload_config()[source]

Reloads application’s configuration

This method reloads application’s configuration including GitHub API token.

repos

Gets GitHub repositories

This method extracts GitHub repositories from the application’s configuration.

Returns:List of GitHub repositories.
Return type:list
labelord.web.finalize_setup()[source]

Finalizes application’s setup

This function makes sure that application’s setup is finalized before the first request.

labelord.web.hook_accept()[source]

Processes POST request

This function processes any POST requests incoming to ‘/’, verifies webhook signature, extracts webhook events and passes them for further processing.

Returns:Empty string.
Return type:str
labelord.web.index()[source]

Processes GET request

This function processes any GET requests incoming to ‘/’ and renders HTML template with a list of GitHub repositories.

Module contents