8.5.15. pymodaq_utils.plugin_checks module

Acceptance checks for PyMoDAQ instrument plugins (pymodaq_plugins_*), without any dependency on pytest.

No hardware is needed: the checks are static / import-level. Use them in a plugin repository with:

from pymodaq_utils.plugin_testing import PluginPackageChecks

class TestMyPlugin(PluginPackageChecks):
    package_name = 'pymodaq_plugins_myinstrument'  # optional, read from the nearest pyproject.toml if omitted

Every check is also exposed as a plain function returning a list of problems (empty if all is fine), see check_move_class, check_viewer_class and check_package_layout.

To get a report without pytest, for any installed plugin package:

from pymodaq_utils.plugin_checks import check_plugin_package
print(check_plugin_package('pymodaq_plugins_mock'))

Added in version 5.3.1.

exception pymodaq_utils.plugin_checks.PluginLoadError(message, environmental=False, placeholder=False, syntax_error=False)[source]

Bases: Exception

A plugin module cannot be imported or does not define the expected class

Variables:
  • environmental (bool) – True if the failure comes from the environment rather than from the plugin code: a third party module or vendor SDK/driver that is not installed or not available on this OS (clr, pyvisa, windll…). The plugin classes cannot be checked then, but this is not necessarily a defect of the plugin.

  • syntax_error (bool) – True if the module has a syntax error: it is located and reported by the static rules (PMQ300)

  • placeholder (bool) – True if the module imports the fake wrapper of the template, that was not replaced yet: this is a todo

class pymodaq_utils.plugin_checks.CheckResult(item, problems=<factory>, warnings=<factory>, findings=<factory>)[source]

Bases: object

Outcome of the checks on one item (the package itself or one of its plugin modules)

problems are defects of the plugin found on the imported classes. warnings mean the item could not be fully checked, for instance because a third party module or a vendor SDK is not available in the current environment. findings come from the static rules of pymodaq_utils.plugin_rules.

Attributes:
ok

Methods

failing([fail_on, strict_imports])

What makes this item fail

failing(fail_on='error', strict_imports=False)[source]

What makes this item fail

Parameters:
  • fail_on (str) – the findings of this level and above fail, see FAIL_LEVELS

  • strict_imports (bool) – if True the modules that could not be imported because of the environment also fail

Return type:

list[str]

findings: list[Finding]
item: str
property ok: bool
problems: list[str]
warnings: list[str]
class pymodaq_utils.plugin_checks.PluginModule(package, module_name, kind)[source]

Bases: object

A plugin module found in a plugin package.

Attributes:
class_name
import_path
name
prefix
property class_name: str
property import_path: str
kind: str
module_name: str
property name: str
package: str
property prefix: str
class pymodaq_utils.plugin_checks.PluginReport(package, results=<factory>, fail_on='error', strict_imports=False)[source]

Bases: object

Result of all the checks on a plugin package, see check_plugin_package()

fail_on sets what makes the report fail, see FAIL_LEVELS. The other findings are just listed.

Attributes:
failures
ok
todos

Methods

format([verbose, max_todos, color])

Text report.

to_dict

format(verbose=False, max_todos=3, color=False)[source]

Text report. The todo findings are summarized unless verbose, colors for a terminal if color

Return type:

str

to_dict()[source]
Return type:

dict

fail_on: str = 'error'
property failures: list[CheckResult]
property ok: bool
package: str
results: list[CheckResult]
strict_imports: bool = False
property todos: list[Finding]
pymodaq_utils.plugin_checks.check_move_class(klass)[source]

Checks on an actuator plugin class

Return type:

list[str]

pymodaq_utils.plugin_checks.check_package_layout(package, check_entry_points=True)[source]

Package name, entry points, mandatory sub-modules and naming of the plugin modules

The entry points only exist once the plugin is installed: set check_entry_points to False before.

Return type:

list[str]

pymodaq_utils.plugin_checks.check_package_sources(package, project=None)[source]

Static rules on the packaging (pyproject.toml…) and on the leftovers of the template

project is the folder of the pyproject.toml, found from the package if not given (only possible if its name matches the package one).

Return type:

CheckResult

pymodaq_utils.plugin_checks.check_plugin_file(path, fail_on='error', strict_imports=False)[source]

Run the checks on a single instrument module of a plugin package (and the todos of this file)

The checks on the package (pyproject.toml, entry points…) are not done, see check_plugin_package(). The package does not need to be installed.

Return type:

PluginReport

pymodaq_utils.plugin_checks.check_plugin_module(plugin_module)[source]

Load a plugin module and run the checks relevant for its kind, plus the static rules on its source

Return type:

CheckResult

pymodaq_utils.plugin_checks.check_plugin_package(package, fail_on='error', strict_imports=False, project=None, check_entry_points=True)[source]

Run all the checks on an installed plugin package and return a report, without using pytest

Parameters:
  • package (str) – name of the plugin package, for instance pymodaq_plugins_mock

  • fail_on (str) – ‘error’ (default), ‘warning’ (also fails on warnings) or ‘todo’ (also on the unfinished parts: TODO comments, placeholders…), see FAIL_LEVELS

  • strict_imports (bool) – if True the modules that cannot be imported because of the environment (missing third party module, SDK or OS specific error) also fail instead of being reported as warnings

  • project (Optional[Path]) – folder of the pyproject.toml of the plugin, if not found from the package

  • check_entry_points (bool) – set to False for a plugin that is not installed yet (see resolve_target())

Return type:

PluginReport

Examples

>>> report = check_plugin_package('pymodaq_plugins_mock')
>>> print(report)
>>> report.ok
pymodaq_utils.plugin_checks.check_viewer_class(klass)[source]

Checks on a detector plugin class

Return type:

list[str]

pymodaq_utils.plugin_checks.find_plugin_modules(package)[source]

Find all plugin modules of a plugin package from the file system (no plugin module is imported).

Modules that don’t follow the naming convention (daq_move_*, daq_{N}viewer_*) are reported by check_package_layout().

Return type:

list[PluginModule]

pymodaq_utils.plugin_checks.guess_package_name(start)[source]

Get the plugin package name from the nearest pyproject.toml above start

The name of the (single) pymodaq_plugins_* folder of the project is used if there is one, as the project name of the pyproject.toml may not have been modified yet, the project name otherwise.

Return type:

str

pymodaq_utils.plugin_checks.is_installed(package)[source]

Whether an entry point of the instrument groups points to the package (so the plugin is installed)

Return type:

bool

pymodaq_utils.plugin_checks.load_plugin_class(plugin_module)[source]

Import a plugin module and return its plugin class

Raises:

PluginLoadError – with an explicit message if the module cannot be imported or lacks the expected class

Return type:

type

pymodaq_utils.plugin_checks.main(argv=None)[source]

Print the report of a plugin package, for the developer: the check_plugin command (or python -m pymodaq_utils.plugin_checks)

Returns 0 if the checks pass, 1 otherwise (so that it can also be used in a script or a CI).

Return type:

int

pymodaq_utils.plugin_checks.resolve_file(path)[source]

Find the plugin module of a python file of a plugin package, without importing it

The folder holding the package is added to sys.path.

Raises:

ValueError – if the file is not in a pymodaq_plugins_* package, or not at the location, or does not have the name, of an instrument module: daq_move_plugins/daq_move_<Name>.py or daq_viewer_plugins/plugins_<N>D/daq_<N>viewer_<Name>.py

Return type:

PluginModule

pymodaq_utils.plugin_checks.resolve_target(target=None)[source]

Find the plugin package to check from a package name or from a folder, without needing it to be installed

Parameters:

target (Optional[str]) – either the name of an importable package, or a folder: the plugin repository (holding the pyproject.toml and the package, in src or not) or the package folder itself. The current folder if not given.

Return type:

tuple[str, Optional[Path]]

Returns:

  • str (the package name, as found in the folder name (so it does not depend on the project name in the) – pyproject.toml, that may not have been modified yet)

  • Path (the folder of the pyproject.toml, if any. The folder holding the package is added to sys.path)

Raises:

ValueError – if no, or several, pymodaq_plugins_* package are found in the folder