univention.ucslint package

Contents

univention.ucslint package#

Submodules#

univention.ucslint.base module#

univention.ucslint.base.noqa(line: str) Callable[[str], bool][source]#

Check for lines to be ignored by ` ucslint: 0000-0`.

>>> noqa('')('0000-0')
False
>>> noqa('# ucslint')('0000-0')
True
>>> noqa('# ucslint: 0000-0')('0000-0')
True
>>> noqa('# ucslint: 0000-1')('0000-0')
False
>>> noqa('# ucslint: 0000-0, 0000-1')('0000-0')
True
univention.ucslint.base.line_regexp(text: str, regexp: Pattern[str]) Iterator[tuple[int, int, Match[str]]][source]#

Find all matches and return row and colum number.

Parameters:
  • text – The text to seach in.

  • regexp – Compiled regular excpression.

Returns:

Iterator returning 3-tuples (row, col, match)

class univention.ucslint.base.UPCMessage(id_: str, msg: str, filename: Path | None = None, row: int | None = None, col: int | None = None)[source]#

Bases: object

Univention Policy Check message.

Parameters:
  • id – Message identifier.

  • msg – Message test.

  • filename – Associated file name.

  • row – Associated line number.

  • col – Associated column number.

getId() str[source]#

Return unique message identifier.

junit() TestCase[source]#

Return JUnit XML test case.

Returns:

test case.

class univention.ucslint.base.UniventionPackageCheckBase[source]#

Bases: object

Abstract base class for checks.

addmsg(msgid: str, msg: str, filename: Path | None = None, row: int | None = None, col: int | None = None, line: str = '') None[source]#

Add UPCMessage message.

Parameters:
  • msgid – Message identifier.

  • msg – Message text.

  • filename – Associated file name.

  • row – Associated line number.

  • col – Associated column number.

  • line – The line content itself (used for per-line ignores).

getMsgIds() dict[str, tuple[int, str]][source]#

Return mapping from message-identifier to 2-tuple (severity, message-text).

setdebug(level: int) None[source]#

Set debug level.

Parameters:

level – Debug level.

debug(msg: str, *args: Any) None[source]#

Print debug message.

Parameters:

msg – Text string.

postinit(path: Path) None[source]#

Checks to be run before real check or to create precalculated data for several runs. Only called once!

Parameters:

path – Directory or file to check.

check_files(paths: Iterable[Path]) None[source]#

The real check.

Parameters:

paths – files to check.

check(path: Path) None[source]#

The real check.

Parameters:

path – Directory or file to check.

result() list[UPCMessage][source]#

Return result as list of messages.

Returns:

List of UPCMessage

class univention.ucslint.base.UniventionPackageCheckDebian[source]#

Bases: UniventionPackageCheckBase

Check for debian/ directory.

check(path: Path) None[source]#

the real check.

exception univention.ucslint.base.UCSLintException[source]#

Bases: Exception

Top level exception.

exception univention.ucslint.base.DebianControlNotEnoughSections[source]#

Bases: UCSLintException

Content exception.

exception univention.ucslint.base.DebianControlParsingError[source]#

Bases: UCSLintException

Parsing exception.

exception univention.ucslint.base.FailedToReadFile(fn: Path)[source]#

Bases: UCSLintException

File reading exception.

class univention.ucslint.base.DebianControlEntry(content: str)[source]#

Bases: dict[str, str]

Handle paragraph in Deb822 control file.

Parameters:

content – String content of paragraph.

RE_MULTILINE = re.compile('$\\n\\s', re.MULTILINE)#
class univention.ucslint.base.DebianControlSource(content: str)[source]#

Bases: DebianControlEntry

Source package entry from debian/control.

property dep#
property dep_indep#
property dep_arch#
property dep_all#
property conf#
property conf_indep#
property conf_arch#
property conf_all#
class univention.ucslint.base.DebianControlBinary(content: str)[source]#

Bases: DebianControlEntry

Binary package entry from debian/control.

property pre#
property dep#
property rec#
property sug#
property all#
property bre#
property enh#
property repl#
property conf#
property pro#
class univention.ucslint.base.ParserDebianControl(filename: Path)[source]#

Bases: object

Parse debian/control file.

Parameters:

filename – Full path.

RE_COMMENT = re.compile('^#.*$\\n?', re.MULTILINE)#
RE_SECTION = re.compile('\\n{2,}', re.MULTILINE)#
class univention.ucslint.base.RegExTest(regex: Pattern[str], msgid: str, msg: str, cntmin: int | None = None, cntmax: int | None = None)[source]#

Bases: object

Regular expression test.

Parameters:
  • regex – Compiled regular expression.

  • msgid – Message identifier.

  • msg – Message text.

  • cntmin – Required minimum number of matches.

  • cntmax – Allowed maximum number of matches.

class univention.ucslint.base.UPCFileTester(maxsize: int = 102400)[source]#

Bases: object

Univention Package Check - File Tester simple class to test if a certain text exists/does not exist in a textfile

By default only the first 100k of the file will be read.

Example:

import re
x = UPCFileTester()
x.addTest(re.compile(r'ext[234]'), '5432-1', 'Habe ein extfs gefunden.', cntmax=0)
x.addTest(re.compile(r'squashfs'), '1234-5', 'Habe kein squashfs gefunden.', cntmin=1)
x.open('/etc/fstab')
msglist = x.runTests()
for msg in msglist:
    print(f'{msg.id} ==> {msg.filename} ==> {msg.msg}')

5432-1: /etc/fstab:4:29: Habe ein extfs gefunden.
5432-1: /etc/fstab:7:19: Habe ein extfs gefunden.
1234-5: /etc/fstab: Habe kein squashfs gefunden.

creates a new UPCFileTester object

Parameters:

maxsize – maximum number of bytes read from specified file

open(filename: Path) None[source]#

Opens the specified file and reads up to maxsize bytes into memory.

Parameters:

filename – File to process.

addTest(regex: Pattern[str], msgid: str, msg: str, cntmin: int | None = None, cntmax: int | None = None) None[source]#

add a new test

Parameters:
  • regex – Compiled regular expression pattern.

  • msgid – msgid for UPCMessage.

  • msg – message for UPCMessage.

  • cntmin – ‘regex’ has to match at least ‘cntmin’ times otherwise a UPCMessage will be added.

  • cntmax – ‘regex’ has to match at most ‘cntmax’ times otherwise a UPCMessage will be added.

Raises:

ValueError – if neither cntmin nor cntmax has been set

runTests() list[UPCMessage][source]#

Runs all given tests on loaded file.

Returns:

a list of UPCMessage objects

class univention.ucslint.base.FilteredDirWalkGenerator(path: Path, ignore_dirs: Iterable[str] | None = None, prefixes: Iterable[str] | None = None, suffixes: Iterable[str] | None = None, ignore_suffixes: Iterable[str] | None = None, ignore_files: Iterable[str] | None = None, reHashBang: Pattern[str] | None = None, readSize: int = 2048)[source]#

Bases: object

FilteredDirWalkGenerator is a generator that walks down all directories and returns all matching filenames.

There are several possibilities to limit returned results:

Parameters:
  • ignore_dirs – a list of additional directory names that will be excluded when traversing subdirectories (e.g. [‘.git’, ‘.svn’])

  • prefixes – a list of prefixes files have to start with (e.g. [‘univention-’, ‘preinst’])

  • suffixes – a list of suffixes files have to end with (e.g. [‘.py’, ‘.sh’, ‘.patch’])

  • ignore_suffixes – a list of additional files, that end with one of defined suffixes, will be ignored (e.g. [‘~’, ‘.bak’])

  • ignore_files – list of additional files that will be ignored (e.g. [‘.gitignore’, ‘config.sub’]).

  • reHashBang – if defined, additionally text files are returned whose first characters match specified regular expression.

  • readSize – number of bytes that will be read for e.g. reHashBang

example:

for fn in FilteredDirWalkGenerator(path, suffixes=['.py']):
  print(fn)
IGNORE_DIRS = {'.git', '.mypy_cache', '.pybuild', '.svn', 'CVS', '__pycache__'}#
IGNORE_SUFFIXES = {'.bak', '.pyc', '.pyo', '.swp', '~'}#
IGNORE_FILES = {'config.guess', 'config.status', 'config.sub', 'configure', 'depcomp', 'install-sh', 'libtool', 'missing'}#
BINARY_SUFFIXES = {'.ai', '.bz2', '.cer', '.class', '.cvd', '.deb', '.der', '.dll', '.efi.signed', '.gd2', '.gif', '.gpg', '.gz', '.ico', '.jar', '.jpeg', '.jpg', '.mo', '.pdf', '.png', '.so', '.svg', '.svgz', '.swf', '.ttf', '.udeb', '.woff', '.xcf', '.xz', '.zip'}#
DOCUMENTATION_SUFFIXES = {'.1', '.2', '.3', '.4', '.5', '.6', '.7', '.8', '.doc', '.html', '.md', '.po', '.rst', '.txt', '.xml', 'ChangeLog', 'README', 'changelog'}#
MAINT_SCRIPT_SUFFIXES = {'postinst', 'postrm', 'preinst', 'prerm'}#

univention.ucslint.common module#

>>> RE_DEBIAN_PACKAGE_NAME.match("0").groups()
('0',)
>>> RE_DEBIAN_PACKAGE_VERSION.match("0").groups()
(None, '0', None)
>>> RE_DEBIAN_PACKAGE_VERSION.match("0-0").groups()
(None, '0', '0')
>>> RE_DEBIAN_PACKAGE_VERSION.match("0-0-0").groups()
(None, '0-0', '0')
>>> RE_DEBIAN_CHANGELOG.match("0 (0) unstable; urgency=low").groups()
('0', '0', ' unstable', ' urgency=low')
>>> RE_HASHBANG_SHELL.match('#!/bin/sh') is not None
True
>>> RE_HASHBANG_SHELL.match('#! /bin/bash') is not None
True

univention.ucslint.main module#

Univention ucslint Check UCS packages for policy compliance.

univention.ucslint.main.load_plugins(opt: Namespace) dict[str, ModuleType][source]#

Load policy checker plugins.

Parameters:

opt – Command line arguments.

Returns:

Mapping of plugin ID to loaded module.

class univention.ucslint.main.DebianPackageCheck(path: Path, plugins: dict[str, ModuleType], debuglevel: int = 0)[source]#

Bases: object

Check Debian package for policy compliance.

Parameters:
  • path – Base directory of Debian package to check.

  • plugins – Mapping of loaded plugins.

  • debuglevel – Vebosity level.

check() None[source]#

Run plugin on files in path.

check_files(files) None[source]#

Run plugin on given files.

loadOverrides() None[source]#

Parse debian/ucslint.overrides file.

in_overrides(msg: UPCMessage) bool[source]#

Check message against overrides.

Parameters:

msg – Message to check.

Returns:

True when the check should be ignored, False otherwise.

printResult(ignore_IDs: Container[str], display_only_IDs: Container[str], display_only_categories: str, exitcode_categories: str, junit: IO[str] | None = None) tuple[int, int][source]#

Print result of checks.

Parameters:
  • ignore_IDs – List of message identifiers to ignore.

  • display_only_IDs – List of message identifiers to display.

  • display_only_categories – List of message categories to display.

  • exitcode_categories – List of message categories to signal as fatal.

  • junit – Generate JUnit XML output to given file.

Returns:

2-tuple (incident-count, exitcode-count)

univention.ucslint.main.clean_id(idstr: str) str[source]#

Format message ID string.

Parameters:

idstr – message identifier.

Returns:

formatted message identifier.

>>> clean_id('1-2')
'0001-2'
univention.ucslint.main.clean_modid(modid: str) str[source]#

Format module ID string.

Parameters:

modid – module number.

Returns:

formatted module number.

>>> clean_modid('1')
'0001'
univention.ucslint.main.clean_msgid(msgid: str) str[source]#

Format message ID string.

Parameters:

msgid – message number.

Returns:

formatted message number.

>>> clean_msgid('01')
'1'
univention.ucslint.main.parse_args(parser: ArgumentParser) Namespace[source]#

Parse command line arguments.

Returns:

parsed options.

univention.ucslint.main.debian_dir(pkgpath: str) Path[source]#

Check if given path is base for a Debian package.

Parameters:

pkgpath – base path.

Returns:

same path.

univention.ucslint.main.run() None[source]#

Run a single given check on selected files.

univention.ucslint.main.main() None[source]#

Run checks.

univention.ucslint.python module#

class univention.ucslint.python.Base[source]#

Bases: object

VER = (0, 0)#
MATCHED_RAW = '\\b(?:[Rr]|[BbFfUu][Rr]|[Rr][BbFf])(?:\'\'\'(?:[^\'\\\\]|\\\\(?:$|.)|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|\\\\(?:$|.)|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|\\\\(?:$|.))*?\'|"(?:[^"\\\\\\n]|\\\\(?:$|.))*?")'#
MATCHED_BYTES = '\\b[Bb](?:\'\'\'(?:[^\'\\\\]|\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2}))*?\'|"(?:[^"\\\\\\n]|\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2}))*?")'#
MATCHED_UNICODE = '(?:\\b[FfUu])?(?:\'\'\'(?:[^\'\\\\]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}))|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}))|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})))*?\'|"(?:[^"\\\\\\n]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})))*?")'#
classmethod matcher() Pattern[str][source]#
class univention.ucslint.python.Python27[source]#

Bases: Base

VER = (2, 7)#
MATCHED_RAW = '\\b(?:[Rr]|[BbUu][Rr]|[Rr][Uu])(?:\'\'\'(?:[^\'\\\\]|\\\\(?:$|.)|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|\\\\(?:$|.)|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|\\\\(?:$|.))*?\'|"(?:[^"\\\\\\n]|\\\\(?:$|.))*?")'#
class univention.ucslint.python.Python30[source]#

Bases: Base

VER = (3, 0)#
MATCHED_RAW = '\\b(?:[Rr]|[Bb][Rr])(?:\'\'\'(?:[^\'\\\\]|\\\\(?:$|.)|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|\\\\(?:$|.)|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|\\\\(?:$|.))*?\'|"(?:[^"\\\\\\n]|\\\\(?:$|.))*?")'#
MATCHED_UNICODE = '(?:\'\'\'(?:[^\'\\\\]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}))|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}))|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})))*?\'|"(?:[^"\\\\\\n]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})))*?")'#
class univention.ucslint.python.Python33[source]#

Bases: Base

VER = (3, 3)#
MATCHED_RAW = '\\b(?:[Rr]|[Bb][Rr]|[Rr][Bb])(?:\'\'\'(?:[^\'\\\\]|\\\\(?:$|.)|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|\\\\(?:$|.)|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|\\\\(?:$|.))*?\'|"(?:[^"\\\\\\n]|\\\\(?:$|.))*?")'#
MATCHED_UNICODE = '(?:\\b[Uu])?(?:\'\'\'(?:[^\'\\\\]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}))|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}))|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})))*?\'|"(?:[^"\\\\\\n]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})))*?")'#
class univention.ucslint.python.Python36[source]#

Bases: Base

VER = (3, 6)#
MATCHED_RAW = '\\b(?:[Rr]|[BbFf][Rr]|[Rr][BbFf])(?:\'\'\'(?:[^\'\\\\]|\\\\(?:$|.)|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|\\\\(?:$|.)|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|\\\\(?:$|.))*?\'|"(?:[^"\\\\\\n]|\\\\(?:$|.))*?")'#
MATCHED_UNICODE = '(?:\\b[FfUu])?(?:\'\'\'(?:[^\'\\\\]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}))|\'[^\']|\'\'[^\'])*?\'\'\'|"""(?:[^"\\\\]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}))|"[^"]|""[^"])*?"""|\'(?:[^\'\\\\\\n]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})))*?\'|"(?:[^"\\\\\\n]|(?:\\\\(?:$|[\\\\\'"abfnrtv]|[0-7]{1,3}|x[0-9a-fA-F]{2})|\\\\(?:N\\{[^}]+\\}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8})))*?")'#
univention.ucslint.python.python_files(path: Path) Iterator[Path][source]#