Font Bakery CheckRunner is the driver of a font bakery suite of checks.

Separation of Concerns Disclaimer: While created specifically for checking fonts and font-families this module has no domain knowledge about fonts. It can be used for any kind of (document) checking. Please keep it so. It will be valuable for other domains as well. Domain specific knowledge should be encoded only in the Profile (Checks, Conditions) and MAYBE in customized reporters e.g. subclasses.

exception fontbakery.checkrunner.APIViolationError(message, result, *args)[source][source]
class fontbakery.checkrunner.CheckRunner(profile, values, values_can_override_profile_names=True, custom_order=None, explicit_checks=None, exclude_checks=None, use_cache=True)[source][source]

order must be a subset of self.order

get(key, iterargs, *args)[source][source]
get_iterarg(name, index)[source][source]

Used by e.g. reporters

property iterargs[source]

uses the singular name as key

property order[source]
property profile[source]
run_externally_controlled(receive_result_fn, next_check_gen, order=None)[source][source]
exception fontbakery.checkrunner.CircularAliasError[source][source]
exception fontbakery.checkrunner.CircularDependencyError[source][source]
exception fontbakery.checkrunner.FailedCheckError(error, *args)[source][source]
exception fontbakery.checkrunner.FailedConditionError(condition, error, *args)[source][source]

This is a serious problem with the check suite profile and it must be solved.

exception fontbakery.checkrunner.FailedDependenciesError(check, error, *args)[source][source]
exception fontbakery.checkrunner.FontBakeryRunnerError[source][source]
exception fontbakery.checkrunner.MissingConditionError(condition_name, error, *args)[source][source]

This is a serious problem with the check suite profile and it must be solved, most probably a typo.

exception fontbakery.checkrunner.MissingValueError[source][source]
exception fontbakery.checkrunner.NamespaceError[source][source]
class fontbakery.checkrunner.Profile(sections=None, iterargs=None, derived_iterables=None, conditions=None, aliases=None, expected_values=None, default_section=None, check_skip_filter=None, profile_tag=None, module_spec=None)[source][source]
add_to_namespace(type, name, value, force=False)[source][source]
auto_register(symbol_table, filter_func=None, profile_imports=None)[source][source]

Register items from symbol_table in the profile.

Get all items from symbol_table dict and from symbol_table.profile_imports if it is present. If they an item is an instance of FontBakeryCheck, FontBakeryCondition or FontBakeryExpectedValue and register it in the default section. If an item is a python module, try to get a profile using get_module_profile(item) and then using merge_profile; If the profile_imports kwarg is given, it is used instead of the one taken from the module namespace.

To register the current module use explicitly:

profile.auto_register(globals()) OR maybe: profile.auto_register(sys.modules[__name__].__dict__)

To register an imported module explicitly:


if filter_func is defined it is called like: filter_func(type, name_or_id, item) where type: one of “check”, “module”, “condition”, “expected_value”, “iterarg”,

“derived_iterable”, “alias”

name_or_id: the name at which the item will be registered.

if type == ‘check’: the if type == ‘module’: the module name (module.__name__)

item: the item to be registered if filter_func returns a falsy value for an item, the item will not be registered.

check_log_override(override_check_id, *args, **kwds)[source][source]
property checks[source]
execution_order(iterargs, custom_order=None, explicit_checks=None, exclude_checks=None)[source][source]
get(name, *args)[source][source]
get_checks_by_dependencies(*dependencies, subset=False)[source][source]

Returns a tuple of all iterags for item, sorted by name.

get_type(name, *args)[source][source]
merge_profile(profile, filter_func=None)[source][source]

Copy all namespace items from profile to self.

Namespace items are: ‘iterargs’, ‘derived_iterables’, ‘aliases’,

‘conditions’, ‘expected_values’

Don’t change any contents of profile ever! That means sections are cloned not used directly

filter_func: see description in auto_register

register_check(section=None, *args, **kwds)[source][source]

Usage: # register in default section @profile.register_check @check(id=’com.example.fontbakery/check/0’) def my_check():

yield PASS, ‘example’

# register in special_section also register that section in the profile @profile.register_check(special_section) @check(id=’com.example.fontbakery/check/0’) def my_check():

yield PASS, ‘example’

register_condition(*args, **kwds)[source][source]


@profile.register_condition @condition def myCondition():

return 123


@profile.register_condition(name=’my_condition’) @condition def myCondition():

return 123

register_expected_value(expected_value, name=None)[source][source]
property sections[source]

Return a json string that can also be used as a key.

The JSON is explicitly unambiguous in the item order entries (dictionaries are not ordered usually) Otherwise it is valid JSON


Set up custom arguments needed for this profile. Return a list of keys that will be set to the values dictonary


Raises SetupError if profile uses any names that are not declared in the its namespace.

test_expected_checks(expected_check_ids, exclusive=False)[source][source]

Self-test to make a sure profile maintainer is aware of changes in the profile. Raises SetupError if expected check ids are missing in the profile (removed) If exclusive=True also raises SetupError if check ids are in the profile that are not in expected_check_ids (newly added).

This is handy if profile.auto_register is used and the profile maintainer is looking for a high level of control over the profile contents, especially for a warning when the profile contents have changed after an update.


Validate values if they are registered as expected_values and present.

  • If they are not registered they shouldn’t be used anywhere at all because profile can self check (profile.check_dependencies) for missing/undefined dependencies.

  • If they are not present in values but registered as expected_values either the expected value has a default value OR a request for that name will raise a KeyError on runtime. We don’t know if all expected values are actually needed/used, thus this fails late.

exception fontbakery.checkrunner.ProtocolViolationError(message, *args)[source][source]
class fontbakery.checkrunner.Section(name, checks=None, order=None, description=None)[source][source]

An ordered set of checks.

Used to structure checks in a profile. A profile consists of one or more sections.


Please use rather register_check as a decorator.

property checks[source]
merge_section(section, filter_func=None)[source][source]

Add section.checks to self, if not skipped by self._add_check_callback. order, description, etc. are not updated.

property order[source]

# register in special_section @my_section.register_check @check(id=’com.example.fontbakery/check/0’) def my_check():

yield PASS, ‘example’

replace_check(override_check_id, new_check)[source][source]
exception fontbakery.checkrunner.SetupError[source][source]
class fontbakery.checkrunner.Status(name, weight=0)[source][source]

If you create a custom Status symbol, please keep in mind that all statuses are registered globally and that can cause name collisions.

However, it’s an intended use case for your checks to be able to yield custom statuses. Interpreters of the check protocol will have to skip statuses unknown to them or treat them in an otherwise non-fatal fashion.

property weight[source]
exception fontbakery.checkrunner.ValueValidationError[source][source]
fontbakery.checkrunner.check_log_override(check, new_id, overrides, reason=None)[source][source]

Returns a new FontBakeryCheck that is decorating (wrapping) check, but with overrides applied to returned statuses when they match.

The new FontBakeryCheck is always a generator check, even if the old check is just a normal function that returns (instead of yields) its result. Also, the new check yields an INFO Status for each overridden original status.


check: the FontBakeryCheck to be decorated new_id: string, must be unique of course and should not(!) be

as we essentially create a new, different check.

overrides: a tuple of override triple-tuples

((override_target, new_status, new_message_string), …) override_target: string, specific Message.code new_status: Status or None, keep old status new_message_string: string or None, keep old message

fontbakery.checkrunner.distribute_generator(gen, targets_callbacks)[source][source]
fontbakery.checkrunner.drive_session_protocol(session_gen, next_check_gen)[source][source]
fontbakery.checkrunner.get_module_profile(module, name=None)[source][source]

Get or create a profile from a module and return it.

If the name module.profile is present the value of that is returned. Otherwise, if the name module.profile_factory is present, a new profile is created using module.profile_factory and then profile.auto_register is called with the module namespace. If neither name is defined, the module is not considered a profile-module and None is returned.

TODO: describe the name argument and better define the signature of profile_factory.

The module argument is expected to behave like a python module. The optional name argument is used when profile_factory is called to give a name to the default section of the new profile. If name is not present module.__name__ is the fallback.

profile_factory is called like this:

profile = module.profile_factory(default_section=default_section)

fontbakery.checkrunner.session_protocol_generator(check_protocol_generator, order)[source][source]