Repository: xlab-si/xopera-opera (language: python)

Issue:
Increase maximum line length within Python code
## Description
Opera is written in Python and while coding it, we were trying to stick to the [PEP8 coding guideline](https://www.python.org/dev/peps/pep-0008/) that also specifies that lines of code need to be wrapped to 79 characters. This wasn't a problem at first but now we have much more code and functionalities. It is evident that 79 is to little space for coding within opera and the developers need to worry about wrapping long lines. So, I propose extending the line limit from 79 to at least 120 characters which would result in more readable code and easier programming. 

## Steps
We have to reformat all Python files and adjust them to the new limit. This can be done efficiently within some IDE.

## Current behaviour
Lines of Python code are limited to 79 characters.

## Expected results
To extend the line-limit to 120 chars and increase code readability.

____
cc @sstanovnik 



Discussion / hints:

Fix patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 9ff825c7..c13e2d4c 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,11 +7,13 @@ commands:
       - checkout
       - run: sudo pip install pipenv
       - run: make init
+      - run: sudo apt-get install -y shellcheck
 
   run_tests:
     description: Run test suite
     steps:
       - common_setup
+      - run: pipenv run ./dev.sh sanity
       - run: make unit_test
       - run: make integration_test
       - run: make examples_test
diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 00000000..7a2f5f88
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,12 @@
+__pycache__/
+
+.eggs/
+*.egg-info/
+*.egg
+dist/
+
+venv/
+.venv/
+docs/_build/
+.pytest_cache/
+.mypy_cache/
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 00000000..f5e9360e
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,86 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+max_line_length = 120
+tab_width = 4
+ij_continuation_indent_size = 8
+ij_formatter_off_tag = @formatter:off
+ij_formatter_on_tag = @formatter:on
+ij_formatter_tags_enabled = false
+ij_smart_tabs = false
+ij_wrap_on_typing = false
+
+[{*.py,*.pyw}]
+ij_python_align_collections_and_comprehensions = true
+ij_python_align_multiline_imports = true
+ij_python_align_multiline_parameters = true
+ij_python_align_multiline_parameters_in_calls = true
+ij_python_blank_line_at_file_end = true
+ij_python_blank_lines_after_imports = 1
+ij_python_blank_lines_after_local_imports = 0
+ij_python_blank_lines_around_class = 1
+ij_python_blank_lines_around_method = 1
+ij_python_blank_lines_around_top_level_classes_functions = 2
+ij_python_blank_lines_before_first_method = 0
+ij_python_dict_alignment = 0
+ij_python_dict_new_line_after_left_brace = false
+ij_python_dict_new_line_before_right_brace = false
+ij_python_dict_wrapping = 1
+ij_python_from_import_new_line_after_left_parenthesis = false
+ij_python_from_import_new_line_before_right_parenthesis = false
+ij_python_from_import_parentheses_force_if_multiline = false
+ij_python_from_import_trailing_comma_if_multiline = false
+ij_python_from_import_wrapping = 1
+ij_python_hang_closing_brackets = false
+ij_python_keep_blank_lines_in_code = 1
+ij_python_keep_blank_lines_in_declarations = 1
+ij_python_keep_indents_on_empty_lines = false
+ij_python_keep_line_breaks = true
+ij_python_new_line_after_colon = false
+ij_python_new_line_after_colon_multi_clause = true
+ij_python_optimize_imports_always_split_from_imports = false
+ij_python_optimize_imports_case_insensitive_order = false
+ij_python_optimize_imports_join_from_imports_with_same_source = false
+ij_python_optimize_imports_sort_by_type_first = true
+ij_python_optimize_imports_sort_imports = true
+ij_python_optimize_imports_sort_names_in_from_imports = false
+ij_python_space_after_comma = true
+ij_python_space_after_number_sign = true
+ij_python_space_after_py_colon = true
+ij_python_space_before_backslash = true
+ij_python_space_before_comma = false
+ij_python_space_before_for_semicolon = false
+ij_python_space_before_lbracket = false
+ij_python_space_before_method_call_parentheses = false
+ij_python_space_before_method_parentheses = false
+ij_python_space_before_number_sign = true
+ij_python_space_before_py_colon = false
+ij_python_space_within_empty_method_call_parentheses = false
+ij_python_space_within_empty_method_parentheses = false
+ij_python_spaces_around_additive_operators = true
+ij_python_spaces_around_assignment_operators = true
+ij_python_spaces_around_bitwise_operators = true
+ij_python_spaces_around_eq_in_keyword_argument = false
+ij_python_spaces_around_eq_in_named_parameter = false
+ij_python_spaces_around_equality_operators = true
+ij_python_spaces_around_multiplicative_operators = true
+ij_python_spaces_around_power_operator = true
+ij_python_spaces_around_relational_operators = true
+ij_python_spaces_around_shift_operators = true
+ij_python_spaces_within_braces = false
+ij_python_spaces_within_brackets = false
+ij_python_spaces_within_method_call_parentheses = false
+ij_python_spaces_within_method_parentheses = false
+ij_python_use_continuation_indent_for_arguments = false
+ij_python_use_continuation_indent_for_collection_and_comprehensions = false
+ij_python_wrap_long_lines = false
+
+[{*.yaml,*.yml}]
+indent_size = 2
+ij_yaml_keep_indents_on_empty_lines = false
+ij_yaml_keep_line_breaks = true
diff --git a/.gitignore b/.gitignore
index 02f8843a..a46bb4fb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,7 @@ eggs/
 dist/
 
 venv/
+.venv/
+docs/_build/
+.pytest_cache/
+.mypy_cache/
diff --git a/.sanity-config.ini b/.sanity-config.ini
new file mode 100644
index 00000000..3a853f25
--- /dev/null
+++ b/.sanity-config.ini
@@ -0,0 +1,651 @@
+[flake8]
+max-line-length = 120
+max-doc-length = 120
+
+exclude = .venv/,.eggs/,dist/
+
+# flake8-import-order
+application-import-names=opera
+application-package-names=
+import-order-style=pep8
+
+
+[mypy]
+# TODO: may be changed in the future for stricter checks
+#       this ignores modules without type information
+ignore_missing_imports = True
+disallow_any_unimported = False
+allow_untyped_globals = False
+
+follow_imports = normal
+
+check_untyped_defs = True
+strict_optional = True
+
+warn_redundant_casts = True
+warn_unused_ignores = True
+warn_no_return = True
+warn_return_any = True
+warn_unreachable = True
+
+show_none_errors = True
+
+strict_equality = True
+
+show_error_context = True
+show_column_numbers = True
+show_error_codes = True
+pretty = True
+color_output = True
+error_summary = True
+show_absolute_path = False
+
+incremental = True
+cache_dir = .mypy_cache
+cache_fine_grained = True
+skip_version_check = False
+skip_cache_mtime_checks = False
+
+warn_unused_configs = True
+
+
+[doc8]
+max-line-length=120
+ignore-path=docs/_build/
+
+
+[pydocstyle]
+convention=pep257
+add-ignore=D100,D101,D102,D103,D104,D105,D107
+
+
+#######################################################################################
+### start of a HUGE pylint configuration block, keep at end of file for readability ###
+#######################################################################################
+[pylint.MASTER]
+
+# A comma-separated list of package or module names from where C extensions may
+# be loaded. Extensions are loading into the active Python interpreter and may
+# run arbitrary code.
+extension-pkg-whitelist=
+
+# Specify a score threshold to be exceeded before program exits with error.
+fail-under=10.0
+
+# Add files or directories to the blacklist. They should be base names, not
+# paths.
+ignore=
+
+# Add files or directories matching the regex patterns to the blacklist. The
+# regex matches against base names, not paths.
+ignore-patterns=
+
+# Python code to execute, usually for sys.path manipulation such as
+# pygtk.require().
+#init-hook=
+
+# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
+# number of processors available to use.
+jobs=0
+
+# Control the amount of potential inferred values when inferring a single
+# object. This can help the performance when dealing with large functions or
+# complex, nested conditions.
+limit-inference-results=100
+
+# List of plugins (as comma separated values of python module names) to load,
+# usually to register additional checkers.
+load-plugins=
+
+# Pickle collected data for later comparisons.
+persistent=yes
+
+# When enabled, pylint would attempt to guess common misconfiguration and emit
+# user-friendly hints instead of false-positive error messages.
+suggestion-mode=yes
+
+# Allow loading of arbitrary C extensions. Extensions are imported into the
+# active Python interpreter and may run arbitrary code.
+unsafe-load-any-extension=no
+
+
+[pylint.MESSAGES CONTROL]
+
+# Only show warnings with the listed confidence levels. Leave empty to show
+# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED.
+confidence=
+
+# Disable the message, report, category or checker with the given id(s). You
+# can either give multiple identifiers separated by comma (,) or put this
+# option multiple times (only on the command line, not in the configuration
+# file where it should appear only once). You can also use "--disable=all" to
+# disable everything first and then reenable specific checks. For example, if
+# you want to run only the similarities checker, you can use "--disable=all
+# --enable=similarities". If you want to run only the classes checker, but have
+# no Warning level messages displayed, use "--disable=all --enable=classes
+# --disable=W".
+disable=print-statement,
+        parameter-unpacking,
+        unpacking-in-except,
+        long-suffix,
+        old-ne-operator,
+        old-octal-literal,
+        import-star-module-level,
+        non-ascii-bytes-literal,
+        raw-checker-failed,
+        bad-inline-option,
+        locally-disabled,
+        file-ignored,
+        suppressed-message,
+        use-symbolic-message-instead,
+        apply-builtin,
+        basestring-builtin,
+        buffer-builtin,
+        cmp-builtin,
+        coerce-builtin,
+        execfile-builtin,
+        file-builtin,
+        long-builtin,
+        raw_input-builtin,
+        reduce-builtin,
+        standarderror-builtin,
+        unicode-builtin,
+        xrange-builtin,
+        coerce-method,
+        delslice-method,
+        getslice-method,
+        setslice-method,
+        no-absolute-import,
+        old-division,
+        dict-iter-method,
+        dict-view-method,
+        next-method-called,
+        metaclass-assignment,
+        indexing-exception,
+        raising-string,
+        reload-builtin,
+        oct-method,
+        hex-method,
+        nonzero-method,
+        cmp-method,
+        input-builtin,
+        round-builtin,
+        intern-builtin,
+        unichr-builtin,
+        map-builtin-not-iterating,
+        zip-builtin-not-iterating,
+        range-builtin-not-iterating,
+        filter-builtin-not-iterating,
+        using-cmp-argument,
+        eq-without-hash,
+        div-method,
+        idiv-method,
+        rdiv-method,
+        exception-message-attribute,
+        sys-max-int,
+        deprecated-types-field,
+        next-method-defined,
+        dict-items-not-iterating,
+        dict-keys-not-iterating,
+        dict-values-not-iterating,
+        xreadlines-attribute,
+        deprecated-sys-function,
+        exception-escape,
+        comprehension-escape,        # OoB rules until here
+        missing-function-docstring,  # manual disables from here
+        missing-module-docstring,
+        missing-class-docstring,
+        fixme,
+        invalid-name,
+        no-else-return,
+        unused-argument,
+        too-few-public-methods,
+        too-many-return-statements,
+        too-many-branches
+
+# Enable the message, report, category or checker with the given id(s). You can
+# either give multiple identifier separated by comma (,) or put this option
+# multiple time (only on the command line, not in the configuration file where
+# it should appear only once). See also the "--disable" option for examples.
+enable=c-extension-no-member
+
+
+[pylint.REPORTS]
+
+# Python expression which should return a score less than or equal to 10. You
+# have access to the variables 'error', 'warning', 'refactor', and 'convention'
+# which contain the number of messages in each category, as well as 'statement'
+# which is the total number of statements analyzed. This score is used by the
+# global evaluation report (RP0004).
+evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
+
+# Template used to display messages. This is a python new-style format string
+# used to format the message information. See doc for all details.
+#msg-template=
+
+# Set the output format. Available formats are text, parseable, colorized, json
+# and msvs (visual studio). You can also give a reporter class, e.g.
+# mypackage.mymodule.MyReporterClass.
+output-format=json
+
+# Tells whether to display a full report or only the messages.
+reports=no
+
+# Activate the evaluation score.
+score=yes
+
+
+[pylint.REFACTORING]
+
+# Maximum number of nested blocks for function / method body
+max-nested-blocks=5
+
+# Complete name of functions that never returns. When checking for
+# inconsistent-return-statements if a never returning function is called then
+# it will be considered as an explicit return statement and no message will be
+# printed.
+never-returning-functions=sys.exit
+
+
+[pylint.BASIC]
+
+# Naming style matching correct argument names.
+argument-naming-style=snake_case
+
+# Regular expression matching correct argument names. Overrides argument-
+# naming-style.
+#argument-rgx=
+
+# Naming style matching correct attribute names.
+attr-naming-style=snake_case
+
+# Regular expression matching correct attribute names. Overrides attr-naming-
+# style.
+#attr-rgx=
+
+# Bad variable names which should always be refused, separated by a comma.
+bad-names=foo,
+          bar,
+          baz,
+          toto,
+          tutu,
+          tata
+
+# Bad variable names regexes, separated by a comma. If names match any regex,
+# they will always be refused
+bad-names-rgxs=
+
+# Naming style matching correct class attribute names.
+class-attribute-naming-style=any
+
+# Regular expression matching correct class attribute names. Overrides class-
+# attribute-naming-style.
+#class-attribute-rgx=
+
+# Naming style matching correct class names.
+class-naming-style=PascalCase
+
+# Regular expression matching correct class names. Overrides class-naming-
+# style.
+#class-rgx=
+
+# Naming style matching correct constant names.
+const-naming-style=UPPER_CASE
+
+# Regular expression matching correct constant names. Overrides const-naming-
+# style.
+#const-rgx=
+
+# Minimum line length for functions/classes that require docstrings, shorter
+# ones are exempt.
+docstring-min-length=-1
+
+# Naming style matching correct function names.
+function-naming-style=snake_case
+
+# Regular expression matching correct function names. Overrides function-
+# naming-style.
+#function-rgx=
+
+# Good variable names which should always be accepted, separated by a comma.
+good-names=i,
+           j,
+           k,
+           ex,
+           Run,
+           _
+
+# Good variable names regexes, separated by a comma. If names match any regex,
+# they will always be accepted
+good-names-rgxs=
+
+# Include a hint for the correct naming format with invalid-name.
+include-naming-hint=yes
+
+# Naming style matching correct inline iteration names.
+inlinevar-naming-style=snake_case
+
+# Regular expression matching correct inline iteration names. Overrides
+# inlinevar-naming-style.
+#inlinevar-rgx=
+
+# Naming style matching correct method names.
+method-naming-style=snake_case
+
+# Regular expression matching correct method names. Overrides method-naming-
+# style.
+#method-rgx=
+
+# Naming style matching correct module names.
+module-naming-style=snake_case
+
+# Regular expression matching correct module names. Overrides module-naming-
+# style.
+#module-rgx=
+
+# Colon-delimited sets of names that determine each other's naming style when
+# the name regexes allow several styles.
+name-group=
+
+# Regular expression which should only match function or class names that do
+# not require a docstring.
+no-docstring-rgx=^_
+
+# List of decorators that produce properties, such as abc.abstractproperty. Add
+# to this list to register other decorators that produce valid properties.
+# These decorators are taken in consideration only for invalid-name.
+property-classes=abc.abstractproperty
+
+# Naming style matching correct variable names.
+variable-naming-style=snake_case
+
+# Regular expression matching correct variable names. Overrides variable-
+# naming-style.
+#variable-rgx=
+
+
+[pylint.LOGGING]
+
+# The type of string formatting that logging methods do. `old` means using %
+# formatting, `new` is for `{}` formatting.
+logging-format-style=new
+
+# Logging modules to check that the string format arguments are in logging
+# function parameter format.
+logging-modules=logging
+
+
+[pylint.MISCELLANEOUS]
+
+# List of note tags to take in consideration, separated by a comma.
+notes=FIXME,
+      XXX,
+      TODO
+
+# Regular expression of note tags to take in consideration.
+#notes-rgx=
+
+
+[pylint.STRING]
+
+# This flag controls whether inconsistent-quotes generates a warning when the
+# character used as a quote delimiter is used inconsistently within a module.
+check-quote-consistency=yes
+
+# This flag controls whether the implicit-str-concat should generate a warning
+# on implicit string concatenation in sequences defined over several lines.
+check-str-concat-over-line-jumps=no
+
+
+[pylint.SIMILARITIES]
+
+# Ignore comments when computing similarities.
+ignore-comments=yes
+
+# Ignore docstrings when computing similarities.
+ignore-docstrings=yes
+
+# Ignore imports when computing similarities.
+ignore-imports=no
+
+# Minimum lines number of a similarity.
+min-similarity-lines=5
+
+
+[pylint.SPELLING]
+
+# Limits count of emitted suggestions for spelling mistakes.
+max-spelling-suggestions=4
+
+# Spelling dictionary name. Available dictionaries: none. To make it work,
+# install the python-enchant package.
+spelling-dict=
+
+# List of comma separated words that should not be checked.
+spelling-ignore-words=
+
+# A path to a file that contains the private dictionary; one word per line.
+spelling-private-dict-file=
+
+# Tells whether to store unknown words to the private dictionary (see the
+# --spelling-private-dict-file option) instead of raising a message.
+spelling-store-unknown-words=no
+
+
+[pylint.VARIABLES]
+
+# List of additional names supposed to be defined in builtins. Remember that
+# you should avoid defining new builtins when possible.
+additional-builtins=
+
+# Tells whether unused global variables should be treated as a violation.
+allow-global-unused-variables=yes
+
+# List of strings which can identify a callback function by name. A callback
+# name must start or end with one of those strings.
+callbacks=cb_,
+          _cb
+
+# A regular expression matching the name of dummy variables (i.e. expected to
+# not be used).
+dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
+
+# Argument names that match this expression will be ignored. Default to name
+# with leading underscore.
+ignored-argument-names=_.*|^ignored_|^unused_
+
+# Tells whether we should check for unused import in __init__ files.
+init-import=no
+
+# List of qualified module names which can have objects that can redefine
+# builtins.
+redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
+
+
+[pylint.TYPECHECK]
+
+# List of decorators that produce context managers, such as
+# contextlib.contextmanager. Add to this list to register other decorators that
+# produce valid context managers.
+contextmanager-decorators=contextlib.contextmanager
+
+# List of members which are set dynamically and missed by pylint inference
+# system, and so shouldn't trigger E1101 when accessed. Python regular
+# expressions are accepted.
+generated-members=
+
+# Tells whether missing members accessed in mixin class should be ignored. A
+# mixin class is detected if its name ends with "mixin" (case insensitive).
+ignore-mixin-members=yes
+
+# Tells whether to warn about missing members when the owner of the attribute
+# is inferred to be None.
+ignore-none=yes
+
+# This flag controls whether pylint should warn about no-member and similar
+# checks whenever an opaque object is returned when inferring. The inference
+# can return multiple potential results while evaluating a Python object, but
+# some branches might not be evaluated, which results in partial inference. In
+# that case, it might be useful to still emit no-member and other checks for
+# the rest of the inferred objects.
+ignore-on-opaque-inference=yes
+
+# List of class names for which member attributes should not be checked (useful
+# for classes with dynamically set attributes). This supports the use of
+# qualified names.
+ignored-classes=optparse.Values,thread._local,_thread._local
+
+# List of module names for which member attributes should not be checked
+# (useful for modules/projects where namespaces are manipulated during runtime
+# and thus existing member attributes cannot be deduced by static analysis). It
+# supports qualified module names, as well as Unix pattern matching.
+ignored-modules=
+
+# Show a hint with possible names when a member name was not found. The aspect
+# of finding the hint is based on edit distance.
+missing-member-hint=yes
+
+# The minimum edit distance a name should have in order to be considered a
+# similar match for a missing member name.
+missing-member-hint-distance=1
+
+# The total number of similar names that should be taken in consideration when
+# showing a hint for a missing member.
+missing-member-max-choices=1
+
+# List of decorators that change the signature of a decorated function.
+signature-mutators=
+
+
+[pylint.FORMAT]
+
+# Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
+expected-line-ending-format=LF
+
+# Regexp for a line that is allowed to be longer than the limit.
+ignore-long-lines=^\s*(# )?<?https?://\S+>?$
+
+# Number of spaces of indent required inside a hanging or continued line.
+indent-after-paren=4
+
+# String used as indentation unit. This is usually "    " (4 spaces) or "\t" (1
+# tab).
+indent-string='    '
+
+# Maximum number of characters on a single line.
+max-line-length=120
+
+# Maximum number of lines in a module.
+max-module-lines=1000
+
+# Allow the body of a class to be on the same line as the declaration if body
+# contains single statement.
+single-line-class-stmt=no
+
+# Allow the body of an if to be on the same line as the test if there is no
+# else.
+single-line-if-stmt=no
+
+
+[pylint.IMPORTS]
+
+# List of modules that can be imported at any level, not just the top level
+# one.
+allow-any-import-level=
+
+# Allow wildcard imports from modules that define __all__.
+allow-wildcard-with-all=no
+
+# Analyse import fallback blocks. This can be used to support both Python 2 and
+# 3 compatible code, which means that the block might have code that exists
+# only in one or another interpreter, leading to false positives when analysed.
+analyse-fallback-blocks=no
+
+# Deprecated modules which should not be used, separated by a comma.
+deprecated-modules=optparse,tkinter.tix
+
+# Create a graph of external dependencies in the given file (report RP0402 must
+# not be disabled).
+ext-import-graph=
+
+# Create a graph of every (i.e. internal and external) dependencies in the
+# given file (report RP0402 must not be disabled).
+import-graph=
+
+# Create a graph of internal dependencies in the given file (report RP0402 must
+# not be disabled).
+int-import-graph=
+
+# Force import order to recognize a module as part of the standard
+# compatibility libraries.
+known-standard-library=
+
+# Force import order to recognize a module as part of a third party library.
+known-third-party=enchant
+
+# Couples of modules and preferred modules, separated by a comma.
+preferred-modules=
+
+
+[pylint.DESIGN]
+
+# Maximum number of arguments for function / method.
+max-args=100
+
+# Maximum number of attributes for a class (see R0902).
+max-attributes=100
+
+# Maximum number of boolean expressions in an if statement (see R0916).
+max-bool-expr=5
+
+# Maximum number of branch for function / method body.
+max-branches=12
+
+# Maximum number of locals for function / method body.
+max-locals=15
+
+# Maximum number of parents for a class (see R0901).
+max-parents=7
+
+# Maximum number of public methods for a class (see R0904).
+max-public-methods=20
+
+# Maximum number of return / yield for function / method body.
+max-returns=5
+
+# Maximum number of statements in function / method body.
+max-statements=50
+
+# Minimum number of public methods for a class (see R0903).
+min-public-methods=1
+
+
+[pylint.CLASSES]
+
+# List of method names used to declare (i.e. assign) instance attributes.
+defining-attr-methods=__init__,
+                      __new__,
+                      setUp,
+                      __post_init__
+
+# List of member names, which should be excluded from the protected access
+# warning.
+exclude-protected=_asdict,
+                  _fields,
+                  _replace,
+                  _source,
+                  _make
+
+# List of valid names for the first argument in a class method.
+valid-classmethod-first-arg=cls
+
+# List of valid names for the first argument in a metaclass class method.
+valid-metaclass-classmethod-first-arg=cls
+
+
+[pylint.EXCEPTIONS]
+
+# Exceptions that will emit a warning when being caught. Defaults to
+# "BaseException, Exception".
+overgeneral-exceptions=BaseException,
+                       Exception
diff --git a/Makefile b/Makefile
index 264be4d5..368ca834 100644
--- a/Makefile
+++ b/Makefile
@@ -16,7 +16,7 @@ export PIPENV_PIPFILE := $(realpath Pipfile)
 
 .PHONY: init
 init:
-	pipenv install -d
+	pipenv install --dev
 
 .PHONY: unit_test
 unit_test:
diff --git a/Pipfile b/Pipfile
index 3f4a8a34..a572faff 100644
--- a/Pipfile
+++ b/Pipfile
@@ -4,6 +4,13 @@ url = "https://pypi.org/simple"
 verify_ssl = true
 
 [dev-packages]
+bandit = "*"
+doc8 = "*"
+flake8 = "*"
+flake8-import-order = "*"
+mypy = "*"
+pydocstyle = "*"
+pylint = "*"
 pytest = "*"
 selinux = "*"
 setuptools = "*"
diff --git a/dev.sh b/dev.sh
new file mode 100755
index 00000000..968b2a17
--- /dev/null
+++ b/dev.sh
@@ -0,0 +1,213 @@
+#!/bin/bash
+
+set -eu
+
+# 1: cd dir
+# 2: args and code dir
+run_pylint() {
+    # we use the column command to format data, but not all shells/distributions have it
+    # so just make a passthrough alias
+    if ! command -v column >/dev/null; then
+        column() {
+            cat
+        }
+    fi
+
+    cd_dir="$1"
+    shift
+    args_and_code_dir="$*"
+
+    cd "$cd_dir"
+    set +e
+    # shellcheck disable=SC2086
+    output=$(pylint --rcfile ../.sanity-config.ini $args_and_code_dir)
+    exit_code="$?"
+    set -e
+    # shellcheck disable=SC2103
+    cd ..
+
+    echo "$output" \
+        | jq -r '.[] | .path + "|" + (.line|tostring) + ":" + (.column|tostring) + "|" + .obj + " |" + ."message-id" + "|" + .symbol + "|" + .message' \
+        | sort --unique \
+        | column -t -s "|"
+
+    return "$exit_code"
+}
+
+run_shellcheck() {
+    files="$(find . -type f -name "*.sh" -not -path "*.venv*")"
+
+    aggregate_exit_code="0"
+    while read -r line; do
+        set +e
+        shellcheck --format tty "$line"
+        exit_code="$?"
+        set -e
+
+        aggregate_exit_code="$((aggregate_exit_code + exit_code))"
+    done <<< "$files"
+
+    return "$aggregate_exit_code"
+}
+
+check_commit_messages() {
+    since=231884e0bb63e764ad23b2e55e5a1e726bc2c11e
+    echo "Checking git messages from $since to HEAD..."
+
+    commits="$(git log "${since}..HEAD" --pretty=format:"%H %s")"
+    echo "Found commits:"
+    echo "$commits"
+    echo
+
+    # shellcheck disable=SC1117
+    commits_with_trailing_period="$(echo -n "$commits" | grep -Ee ".*\.\s*$")"
+
+    if [ -z "$commits_with_trailing_period" ]; then
+        number_of_trailing_periods=0
+    else
+        number_of_trailing_periods="$(echo "$commits_with_trailing_period" | wc -l)"
+    fi
+
+    echo "Found $number_of_trailing_periods commits with a trailing period"
+    echo "$commits_with_trailing_period"
+    echo
+
+    if [ "$number_of_trailing_periods" -gt 0 ]; then
+        echo "Commits must not have a trailing period in their commit summary."
+        return 7
+    fi
+    return 0
+}
+
+run_sanity() {
+    set +e
+
+    echo "Running pylint (source)"
+    output_pylint_src=$(run_pylint src/ opera/)
+    code_pylint_src="$?"
+
+    echo "Running pylint (tests)"
+    output_pylint_test=$(run_pylint tests/ --disable no-self-use --disable expression-not-assigned unit/)
+    code_pylint_test="$?"
+
+    echo "Running flake8"
+    output_flake8=$(flake8 --statistics --config .sanity-config.ini)
+    code_flake8="$?"
+
+    echo "Running mypy"
+    output_mypy=$(mypy --config-file .sanity-config.ini src/opera/ tests/unit/)
+    code_mypy="$?"
+
+    echo "Running bandit"
+    output_bandit=$(bandit --recursive --aggregate file --format txt src/opera/ 2>&1)
+    code_bandit="$?"
+
+    echo "Running doc8"
+    output_doc8=$(doc8 --config .sanity-config.ini docs/)
+    code_doc8="$?"
+
+    echo "Running pydocstyle"
+    output_pydocstyle=$(pydocstyle --count --explain --config .sanity-config.ini src/opera/)
+    code_pydocstyle="$?"
+
+    echo "Running shellcheck"
+    output_shellcheck=$(run_shellcheck)
+    code_shellcheck="$?"
+
+    echo "Checking commit messages"
+    output_commit_messages=$(check_commit_messages)
+    code_commit_messages="$?"
+
+    set -e
+
+    echo "pylint (src) output"
+    echo "$code_pylint_src"
+    echo "$output_pylint_src"
+    echo "### pylint (tests) output ###"
+    echo "exit code: $code_pylint_test"
+    echo "$output_pylint_test"
+    echo "### flake8 output ###"
+    echo "exit code: $code_flake8"
+    echo "$output_flake8"
+    echo "### shellcheck output ###"
+    echo "exit code: $code_shellcheck"
+    echo "$output_shellcheck"
+    echo "### mypy output ###"
+    echo "exit code: $code_mypy"
+    echo "$output_mypy"
+    echo "### bandit output ###"
+    echo "exit code: $code_bandit"
+    echo "$output_bandit"
+    echo "### doc8 output ###"
+    echo "exit code: $code_doc8"
+    echo "$output_doc8"
+    echo "### pydocstyle output ###"
+    echo "exit code: $code_pydocstyle"
+    echo "$output_pydocstyle"
+    echo "### shellcheck output ###"
+    echo "exit code: $code_shellcheck"
+    echo "$output_shellcheck"
+    echo "### commit message check output ###"
+    echo "exit code: $code_commit_messages"
+    echo "$output_commit_messages"
+
+    echo "Applied overrides:"
+    grep -rinEe "noqa:|pylint:|nosec|# shellcheck" \
+        --exclude-dir ".venv/" \
+        --exclude-dir ".eggs/" \
+        --exclude-dir ".git/" \
+        --exclude-dir ".mypy_cache/" \
+        --exclude-dir ".pytest_cache/" \
+        .
+
+    combined_exit_code="$((
+        code_pylint_src
+        + code_pylint_test
+        + code_flake8
+        + code_mypy
+        + code_bandit
+        + code_doc8
+        + code_pydocstyle
+        + code_shellcheck
+        + code_commit_messages
+    ))"
+    exit "$combined_exit_code"
+}
+
+run_unit() {
+    pytest tests/unit/
+}
+
+build_local_ci_container() {
+    docker build -t xopera-opera-test --file - . <<EOF
+FROM circleci/python:3.8
+USER root
+WORKDIR /test/
+RUN sudo apt-get install -y \
+    shellcheck
+COPY Pipfile /test/Pipfile-complete
+RUN head -n -3 Pipfile-complete > Pipfile \
+    && pipenv install --dev
+
+COPY . /test/
+RUN pipenv install
+EOF
+}
+
+command="$1"
+shift
+
+case "$command" in
+    sanity)
+        run_sanity
+        ;;
+    unit)
+        run_unit
+        ;;
+    integration)
+        build_local_ci_container
+        ;;
+    *)
+        echo "Help."
+        ;;
+esac
diff --git a/docs/business-value.rst b/docs/business-value.rst
index bbda8d1d..28fbaef6 100644
--- a/docs/business-value.rst
+++ b/docs/business-value.rst
@@ -5,11 +5,14 @@ Business value
 **************
 
 Orchestrator xOpera is a tool that follows OASIS TOSCA standard and unlocks its benefits of providing multi-cloud
-orchestration support. According to this business value of this tool can be seen through different perspectives. Firstly,
-the aim is to have an orchestration tool which is easy to install and easy to use. Installation process is very simple
-and requires only python and possibly a virtual environment. Opera package is visible on PyPI so even older versions
-can be installed. Secondly, opera is a very dynamic tool which can be used for simple or complex orchestration of
-applications because one can prepare his own TOSCA templates that are unique and based on his use case. All
-of the templates can also be modified and reused with xOpera. And lastly, as opera is evolving, there are many different
-CLI commands that can be used with it. Besides deploying and undeploying a solution, opera can be used for TOSCA CSAR
-service template validation or for printing out outputs of the orchestration.
+orchestration support.
+According to this business value of this tool can be seen through different perspectives.
+Firstly, the aim is to have an orchestration tool which is easy to install and easy to use.
+Installation process is very simple and requires only python and possibly a virtual environment.
+Opera package is visible on PyPI so even older versions can be installed.
+Secondly, opera is a very dynamic tool which can be used for simple or complex orchestration of applications because
+one can prepare his own TOSCA templates that are unique and based on his use case.
+All of the templates can also be modified and reused with xOpera.
+And lastly, as opera is evolving, there are many different CLI commands that can be used with it.
+Besides deploying and undeploying a solution, opera can be used for TOSCA CSAR service template validation or for
+printing out outputs of the orchestration.
diff --git a/docs/examples.rst b/docs/examples.rst
index 66c3b0c4..ead534c8 100755
--- a/docs/examples.rst
+++ b/docs/examples.rst
@@ -6,9 +6,9 @@ Examples
 
 In this section we show some simple examples of orchestrating with xOpera.
 
-===========================
-Private cloud 
-===========================
+=============
+Private cloud
+=============
 
 OpenStack client setup
 ######################
@@ -38,16 +38,16 @@ in playbooks that implement life cycle operations.
     to connect.
 
 
-============================
-Public cloud 
-============================
+============
+Public cloud
+============
 
 TBD
 
 
-============================
+==========
 Serverless
-============================
+==========
 
 
 Screencast video
@@ -63,9 +63,9 @@ solution to AWS Lambda:
     </div>
 
 
-============================
+===
 HPC
-============================
+===
 
 
 =============================
@@ -78,9 +78,9 @@ TOSCA CSAR
 
 TBD.
 
-This example shows a deployment of the compressed TOSCA CSAR (available here: :download:`big.csar </files/csars/big/big.csar>`).
-The result of the example consisting of deploy, outputs and undeploy operations
-is shown below.
+This example shows a deployment of the compressed TOSCA CSAR
+(available here: :download:`big.csar </files/csars/big/big.csar>`).
+The result of the example consisting of deploy, outputs and undeploy operations is shown below.
 
 .. code-block:: console
 
diff --git a/docs/files/csars/small/inputs.json b/docs/files/csars/small/inputs.json
index 7eac6022..02525da3 100644
--- a/docs/files/csars/small/inputs.json
+++ b/docs/files/csars/small/inputs.json
@@ -1,4 +1,4 @@
 {
-"host_ip": "localhost",
-"relationship_input": "Hey, I am in relationship!"
+    "host_ip": "localhost",
+    "relationship_input": "Hey, I am in relationship!"
 }
diff --git a/docs/index.rst b/docs/index.rst
index 7514a117..8f0c1fb8 100755
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -15,9 +15,9 @@ The following documentation explains the usage of xOpera TOSCA orchestrator. Wan
     opera_api
     template_library
     examples
-    
-     
-     
+
+
+
 ..
    Indices and tables
    ==================
diff --git a/docs/introduction.rst b/docs/introduction.rst
index 0e19d4e2..52c5ee59 100755
--- a/docs/introduction.rst
+++ b/docs/introduction.rst
@@ -4,16 +4,22 @@
 Introduction
 ************
 
-``xOpera project`` includes a set of tools for advanced orchestration, with an orchestration tool ``xOpera orchestrator`` or shorter ``opera``.
+``xOpera project`` includes a set of tools for advanced orchestration
+with an orchestration tool ``xOpera orchestrator`` or shorter ``opera``.
 
 ``opera`` aims to be a lightweight orchestrator compliant with `OASIS TOSCA <https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=tosca>`_.
 and the current compliance is with the `TOSCA Simple Profile in YAML v1.3 <https://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.3/TOSCA-Simple-Profile-YAML-v1.3.html>`_.
 ``opera`` is by following TOSCA primarily a (TOSCA) cloud orchestrator which enables orchestration of automated tasks
 within cloud applications for different cloud providers such as Amazon Web Services(AWS), Microsoft Azure, Google Cloud
-Platform(GCP), OpenFaaS, OpenStack and so on. Apart from that this tool can be used and integrated to other infrastructures
-in order to orchestrate services or applications and therefore reduce human factor.
+Platform(GCP), OpenFaaS, OpenStack and so on.
+Apart from that this tool can be used and integrated to other infrastructures in order to orchestrate services or
+applications and therefore reduce human factor.
 
-xOpera orchestrator engine - called xOpera library - xOpera CLI and xOpera API are an open-source project which currently reside on GitHub inside `xopera-opera <https://github.com/xlab-si/xopera-opera>`_ and `xopera-opera <https://github.com/xlab-si/xopera-api>`_repositories. As an orchestration tool xOpera uses `Ansible automation tool <https://www.ansible.com/>`_ to implement the TOSCA standard and to run its operations via Ansible playbook actuators which again opens a lot of new possibilities.
+xOpera orchestrator engine - called xOpera library - xOpera CLI and xOpera API are an open-source project which
+currently reside on GitHub inside `xopera-opera <https://github.com/xlab-si/xopera-opera>`_
+and `xopera-opera <https://github.com/xlab-si/xopera-api>`_repositories.
+As an orchestration tool xOpera uses `Ansible automation tool <https://www.ansible.com/>`_ to implement the TOSCA
+standard and to run its operations via Ansible playbook actuators which again opens a lot of new possibilities.
 
 .. _xopera_architecture:
 
@@ -27,15 +33,12 @@ xOpera orchestrator engine - called xOpera library - xOpera CLI and xOpera API a
 Currently a set of components is presented in figure :numref:`xopera_architecture`, where we can point out:
 
 
- - Opera CLI
- 	is a command line interface to the **xOpera library** for deploying TOSCA templates and CSARs
- - Opera API 
- 	allows integration of **xOpera library**. 
- - xOpera SaaS
- 	is a standalone service for application lifecycle management with xOpera orchestrator through GUI and API.
- - TPS or Template Publishing Service  
-  	is a library of published TOSCA templates and CSARs
-  
+ - Opera CLI is a command line interface to the **xOpera library** for deploying TOSCA templates and CSARs
+ - Opera API allows integration of **xOpera library**.
+ - xOpera SaaS is a standalone service for application lifecycle management with xOpera orchestrator
+   through GUI and API.
+ - TPS or Template Publishing Service is a library of published TOSCA templates and CSARs
+
 Each component is covered by corresponding This documentation will cover all xOpera components.
 
 ================
@@ -43,8 +46,9 @@ Background
 ================
 
 xOpera is a TOSCA standard compliant orchestrator that is following the paradigm of having a minimal set of
-features and is currently focusing on Ansible. xOpera is following the traditional UNIX philosophy of having a tool that
-does one thing, and does it right. So, with a minimal set of features xOpera will do just the orchestration, and do it well.
+features and is currently focusing on Ansible.
+xOpera is following the traditional UNIX philosophy of having a tool that does one thing, and does it right.
+So, with a minimal set of features xOpera will do just the orchestration, and do it well.
 
 xOpera is available on GitHub under Apache License 2.0.
 
@@ -75,7 +79,7 @@ Parser
 
 .. note::
 
-    *TBD*: This part of the documentation will be improved in the future. 
+   *TBD*: This part of the documentation will be improved in the future.
 
 xOpera orchestrator has its own YAML and TOSCA parser which is shown on the image below :ref:`opera_parser_structure`.
 
diff --git a/docs/opera_api.rst b/docs/opera_api.rst
index 6f9a2852..38b9a7c4 100755
--- a/docs/opera_api.rst
+++ b/docs/opera_api.rst
@@ -1,33 +1,33 @@
-.. _opera api:
-
-***********
-xOpera API
-***********
-
-=================
-Installation
-=================
-This section explains the installation of xOpera orchestrator API.
-
-
-
-**Prerequisites**
-
-
-``opera`` requires python 3 and a virtual environment. In a typical modern
-Linux environment, we should already be set. In Ubuntu, however, we might need
-to run the following commands::
-
-  $ sudo apt update
-  $ sudo apt install -y python3-venv python3-wheel python-wheel-common
-
-**Install**
-
-
-xOpera is distributed as Python package that is regularly published on `PyPI <https://pypi.org/project/opera-api/>`_.
-So the simplest way to test ``opera-api`` is to install it into virtual environment::
-
-  $ mkdir ~/opera && cd ~/opera
-  $ python3 -m venv .venv && . .venv/bin/activate
-  (.venv) $ pip install opera-api
-
+.. _opera api:
+
+***********
+xOpera API
+***********
+
+=================
+Installation
+=================
+This section explains the installation of xOpera orchestrator API.
+
+
+
+**Prerequisites**
+
+
+``opera`` requires python 3 and a virtual environment. In a typical modern
+Linux environment, we should already be set. In Ubuntu, however, we might need
+to run the following commands::
+
+  $ sudo apt update
+  $ sudo apt install -y python3-venv python3-wheel python-wheel-common
+
+**Install**
+
+
+xOpera is distributed as Python package that is regularly published on `PyPI <https://pypi.org/project/opera-api/>`_.
+So the simplest way to test ``opera-api`` is to install it into virtual environment::
+
+  $ mkdir ~/opera && cd ~/opera
+  $ python3 -m venv .venv && . .venv/bin/activate
+  (.venv) $ pip install opera-api
+
diff --git a/docs/opera_cli.rst b/docs/opera_cli.rst
index b4a63b60..d186b0cb 100755
--- a/docs/opera_cli.rst
+++ b/docs/opera_cli.rst
@@ -1,712 +1,714 @@
-.. _Opera CLI:
-
-******************
-xOpera CLI (opera)
-******************
-
-.. _Opera CLI install:
-
-=================
-Installation
-=================
-
-This section explains the installation of xOpera orchestrator.
-
-**Prerequisites**
-
-
-``opera`` requires python 3 and a virtual environment. In a typical modern
-Linux environment, we should already be set. In Ubuntu, however, we might need
-to run the following commands::
-
-  $ sudo apt update
-  $ sudo apt install -y python3-venv python3-wheel python-wheel-common
-
-**Install**
-
-
-xOpera is distributed as Python package that is regularly published on `PyPI <https://pypi.org/project/opera/>`_.
-So the simplest way to test ``opera`` is to install it into virtual environment::
-
-  $ mkdir ~/opera && cd ~/opera
-  $ python3 -m venv .venv && . .venv/bin/activate
-  (.venv) $ pip install opera
-
-
-====================================
-Secrets and Environment variables
-====================================
-
-
-
-You can use the following environment variables:
-
-+-----------------------------------+--------------------------------+---------------------------+
-| Environment variable              | Description                    | Example value             |
-+===================================+================================+===========================+
-| | ``OPERA_SSH_USER``              | | Username for the Ansible ssh | | ``ubuntu``              |
-| |                                 | | connection to a remote VM    | | (default is ``centos``) |
-+-----------------------------------+--------------------------------+---------------------------+
-| | ``OPERA_SSH_IDENTITY_FILE``     | | Path to the file containing  | | ``~/.ssh/id_ed25519``   |
-| |                                 | | your private ssh key that    | |                         |
-| |                                 | | will be used for a           | |                         |
-| |                                 | | connection to a remote VM    | |                         |
-+-----------------------------------+--------------------------------+---------------------------+
-| | ``OPERA_SSH_HOST_KEY_CHECKING`` | | Disable Ansible host key     | | ``false`` or ``f``      |
-| |                                 | | checking (not recommended)   | | (not case sensitive)    |
-+-----------------------------------+--------------------------------+---------------------------+
-
-.. danger::
-
-   Be very careful with your orchestration secrets (such as SSH private keys,
-   cloud credentials, passwords ans so on) that are stored as opera inputs.
-   To avoid exposing them don't share the inputs file and the created opera
-   storage folder with anyone.
-
-.. tip::
-
-   If you have any problems have a look at the existing issues here: https://github.com/xlab-si/xopera-opera/issues
-   or open a new one yourself.
-
-
-
-.. _CLI Reference:
-
-===========================
-CLI reference and examples 
-===========================
-
-``opera`` was  originally meant to be used in a terminal as a client and it
-currently allows users to execute the following commands:
-
-+---------------------+----------------------------------------------+
-| CLI command         | Purpose and description                      |
-+=====================+==============================================+
-| ``opera deploy``    | deploy TOSCA service template or CSAR        |
-+---------------------+----------------------------------------------+
-| ``opera undeploy``  | undeploy TOSCA service template or CSAR      |
-+---------------------+----------------------------------------------+
-| ``opera validate``  | validate TOSCA service template or CSAR      |
-+---------------------+----------------------------------------------+
-| ``opera outputs``   | retrieve outputs from service template       |
-+---------------------+----------------------------------------------+
-| ``opera info``      | show information about the current project   |
-+---------------------+----------------------------------------------+
-| ``opera package``   | retrieve outputs from service template       |
-+---------------------+----------------------------------------------+
-| ``opera unpackage`` | retrieve outputs from service template       |
-+---------------------+----------------------------------------------+
-| ``opera init``      | initialize the service template or CSAR      |
-+---------------------+----------------------------------------------+
-
-The commands can be executed in a random order and the orchestrator will warn  and the orchestrator will warn you in case if any problems. Each CLI command is described more in detail in the following sections.
-
-
-deploy
-######
-
-**Name**
-
-``deploy`` - used to deploy and control deployment of the application described in YAML or CSAR.
-
-**Usage**
-
-      .. argparse::
-         :filename: src/opera/cli.py
-         :func: create_parser
-         :prog: opera
-         :path: deploy
-
-         The ``--resume/-r`` and ``--clean-state/-c`` options are mutually exclusive.
-
-
-.. tabs::
-
-   .. tab:: Example
-
-      A simple deployment of TOSCA service template is shown on the next image (:numref:`opera_deploy_service_template_svg`).
-
-      .. _opera_deploy_service_template_svg:
-
-      .. figure:: /images/opera_deploy_service_template.svg
-         :target: _images/opera_deploy_service_template.svg
-         :width: 100%
-         :align: center
-
-         Example of `hello world <https://github.com/xlab-si/xopera-opera/tree/master/examples/hello>`_ template opera deployment.
-
-      Another example (:numref:`opera_deploy_csar_svg`) is below and shows a more
-      complex usage of ``opera deploy`` command, deploying the compressed TOSCA
-      CSAR with inputs and additional CLI flags. The CSAR is first deployed with
-      the supplied `YAML inputs <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/inputs.yaml>`_
-      (using ``--inputs/-i`` flag) and with two workers (``--workers/-w`` switch)
-      that can run two Ansible playbook operations simultaneously. Then the CSAR
-      is deployed again (using the ``--clean-state/-c`` option) from the beginning,
-      but the execution gets interrupted. Therefore the third deployment is used
-      to resume the deployment process from where it was interrupted (using the
-      ``--resume/-r`` flag, we also used ``--force/-f`` flag here to skip all
-      yes/no prompts).
-
-      .. _opera_deploy_csar_svg:
-
-      .. figure:: /images/opera_deploy_csar.svg
-         :target: _images/opera_deploy_csar.svg
-         :width: 100%
-         :align: center
-
-         The `big CSAR <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/big.csar>`_ example deployment.
-
-   .. tab:: Source
-
-   		CLI instructions for example
-
-   		.. code-block:: bash 
-   		
-   			cd xopera-opera/examples/hello
-   			opera deploy service.yaml
-   			opera undeploy
-
-   		.. hint:: 
-   			Instead of ``service.yaml`` you can deploy a compressed TOSCA CSAR directly with ``deploy`` command.
-
-
-
-
-   .. tab:: Details
-
-      The ``opera deploy`` command is used to initiate the deployment
-      orchestration process using the supplied TOSCA service template or the
-      compressed TOSCA CSAR. Within this CLI command the xOpera orchestrator
-      invokes multiple `TOSCA interface operations <https://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.3/cos01/TOSCA-Simple-Profile-YAML-v1.3-cos01.html#_Toc26969470>`_
-      (TOSCA `Standard interface` node operations and also TOSCA `Configure interface`
-      relationship operations). The operations are executed in the following order:
-
-      1. ``create``
-      2. ``pre_configure_source``
-      3. ``pre_configure_target``
-      4. ``configure``
-      5. ``post_configure_source``
-      6. ``post_configure_target``
-      7. ``start``
-
-      The operation gets executed if it is defined within the TOSCA service template
-      and has a link to the corresponding Ansible playbook.
-
-      After the deployment the following files and folders will be created in
-      your opera storage directory (by default that is ``.opera`` and can be
-      changed using the ``--instance-path`` flag):
-
-      - ``root_file`` file - contains the path to the service template or CSAR
-      - ``inputs`` file - JSON file with the supplied inputs
-      - ``instances`` folder - includes JSON files that carry the information about the status of TOSCA node and relationship instances
-      - ``csars`` folder contains the extracted copy of your CSAR (created only if you deployed the compressed TOSCA CSAR)
-
-
-
-
-
-
-undeploy
-#########
-
-**Name**
-
-
-``undeploy`` - undeploys application; removes all application instances and components.
-
-**Usage**
-
-      .. argparse::
-         :filename: src/opera/cli.py
-         :func: create_parser
-         :prog: opera
-         :path: undeploy
-
-         The ``opera undeploy`` command does not take any positional arguments.
-
-
-.. tabs::
-
-   .. tab:: Example
-
-      A simple undeployment process of TOSCA service template is shown on the
-      next image (:numref:`opera_undeploy_svg`). The service template should
-      be deployed first and the you can undeploy the solution.
-
-      .. _opera_undeploy_svg:
-
-      .. figure:: /images/opera_cli.svg
-         :target: _images/opera_cli.svg
-         :width: 100%
-         :align: center
-
-         Example showing `hello <https://github.com/xlab-si/xopera-opera/tree/master/examples/hello>`_ template opera undeployment.
-
-      Another example (:numref:`opera_undeploy_csar_svg`) is below and shows a more
-      complex usage of ``opera undeploy`` command, undeploying the compressed TOSCA
-      CSAR with additional CLI flags. The CSAR was first deployed with the supplied
-      `inputs file <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/inputs.yaml>`_
-      Then the CSAR is undeployed, but the execution gets interrupted. To resume
-      the undeployment process from where it was interrupted the ``--resume/-r``
-      flag is used.
-
-      .. _opera_undeploy_csar_svg:
-
-      .. figure:: /images/opera_undeploy_csar.svg
-         :target: _images/opera_undeploy_csar.svg
-         :width: 100%
-         :align: center
-
-         The undeployment of the `big CSAR example <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/big.csar>`_.
-
-   .. tab:: Source
-
-   		CLI instructions for example
-
-   		.. code-block:: bash 
-   		
-   			cd xopera-opera/examples/hello
-   			opera deploy service.yaml
-   			opera undeploy
-   			# If undeploy was interrupted
-   			opera undeploy -r
-
-   		.. hint:: 
-   			Instead of ``service.yaml`` you can deploy a compressed TOSCA CSAR directly with ``deploy`` command.
-
-
-   .. tab:: Details
-
-      The ``opera undeploy`` command is used to tear down the deployed blueprint.
-      Within the undeployment process the xOpera orchestrator invokes two TOSCA
-      Standard interface node operations in the following order:
-
-      1. ``stop``
-      2. ``delete``
-
-      The operation gets executed if it is defined within the TOSCA service template
-      and has a link to the corresponding Ansible playbook.
-
-
-
-validate
-########
-
-**Name**
-
-Validates the structure of TOSCA template or CSAR
-
-**Usage**
-      .. argparse::
-         :filename: src/opera/cli.py
-         :func: create_parser
-         :prog: opera
-         :path: validate
-
-
-.. tabs::
-
-   .. tab:: Example
-
-      The first image below (:numref:`opera_validate_service_template_svg`) shows an example of
-      TOSCA service template validation.
-
-      .. _opera_validate_service_template_svg:
-
-      .. figure:: /images/opera_validate_service_template.svg
-         :target: _images/opera_validate_service_template.svg
-         :width: 100%
-         :align: center
-
-         Example showing `attribute mapping <https://github.com/xlab-si/xopera-opera/tree/master/examples/attribute_mapping>`_ template validation.
-
-      The second image (:numref:`opera_validate_csar_svg`) shows an example of
-      TOSCA zipped CSAR validation where orchestration YAML inputs file is also supplied.
-
-      .. _opera_validate_csar_svg:
-
-      .. figure:: /images/opera_validate_csar.svg
-         :target: _images/opera_validate_csar.svg
-         :width: 100%
-         :align: center
-
-         Example showing `big <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/big.csar>`_ CSAR validation.
-
-   .. tab:: Source
-
-   		CLI instructions for example
-
-   		.. code-block:: bash 
-   		
-   			cd xopera-opera/examples/attribute_mapping
-   			opera validate service yaml
-
-   			opera validate -i inputs.yaml big.csar
-
-   		.. hint:: 
-   			Instead of ``service.yaml`` you can deploy a compressed TOSCA CSAR directly with ``deploy`` command.
-
-
-   .. tab:: Overview
-
-      With ``opera validate`` you can validate any TOSCA template or CSAR and
-      find out whether it's properly structured and deployable by opera. At the
-      end of this operation you will receive the validation result where opera
-      will warn you about TOSCA template inconsistencies if there was any.
-
-   
-outputs
-#######
-
-
-**Name**
-
-``outputs`` Print the outputs of the deploy/undeploy.
-
-**Usage**
-
-
-      .. argparse::
-         :filename: src/opera/cli.py
-         :func: create_parser
-         :prog: opera
-         :path: outputs
-
-.. tabs::
-
-   .. tab:: Example
-
-      The image below (:numref:`opera_outputs_service_template_svg`) shows an
-      example of retrieving the orchestration outputs after the deployment process.
-
-      .. _opera_outputs_service_template_svg:
-
-      .. figure:: /images/opera_outputs_service_template.svg
-         :target: _images/opera_outputs_service_template.svg
-         :width: 100%
-         :align: center
-
-         Example showing `orchestration outputs <https://github.com/xlab-si/xopera-opera/tree/master/examples/outputs>`_ retrieval.
-
-      Another example in the figure below (:numref:`opera_outputs_csar_svg`)
-      shows deploying the TOSCA CSAR with the supplied
-      `JSON inputs file <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/inputs.json>`_.
-      After that the outputs are retrieved and formatted in JSON (using ``--format/-f`` option).
-
-      .. _opera_outputs_csar_svg:
-
-      .. figure:: /images/opera_outputs_csar.svg
-         :target: _images/opera_outputs_csar.svg
-         :width: 100%
-         :align: center
-
-         Example showing `small CSAR <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/small.csar>`_ deployment and outputs retrieval.
-
-   .. tab:: Details
-
-      The ``opera outputs`` command lets you access the orchestration outputs
-      defined in the TOSCA service template and print them out to the console
-      in JSON or YAML format.
-
-  
-
-
-info
-#######
-
-**Name**
-
-``info`` - print the details of current deployment project
-
-**Usage**
-
-      .. argparse::
-         :filename: src/opera/cli.py
-         :func: create_parser
-         :prog: opera
-         :path: info
-
-
-.. tabs::
-
-   .. tab:: Example
-
-      A minimal ``opera info`` example is shown on the image below (:numref:`opera_info_minimal_svg`).
-      The service template is deployed first with the debug mode turned on
-      (``--verbose/-v`` flag is used, which prints out the inputs and the
-      Ansible playbook tasks outputs). Then ``opera info`` command is used to
-      print out the information about the current opera project.
-
-      .. _opera_info_minimal_svg:
-
-      .. figure:: /images/opera_info_minimal.svg
-         :target: _images/opera_info_minimal.svg
-         :width: 100%
-         :align: center
-
-         Testing opera info on the `capability_attributes_properties example <https://github.com/xlab-si/xopera-opera/tree/master/examples/capability_attributes_properties>`_.
-
-      A more complex example (:numref:`opera_info_full_svg`) is below and shows a
-      combined usage of init, deploy and undeploy commands on the zipped TOSCA
-      CSAR with additional CLI flags. After every operation ``opera info`` CLI
-      command is called to explore the current status of the project.
-
-      The CSAR was first initialized without the inputs. Those (in `inputs.json file <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/inputs.json>`_)
-      were supplied within the second deployment step, which gets interrupted
-      and this affects the current project state. To resume the deployment
-      process from where it was interrupted the ``--resume/-r`` flag is used.
-      Then the CSAR is undeployed. The ``opera info`` output is printed
-      out in both YAML and JSON formats (here ``--format/-f`` is used).
-
-      .. _opera_info_full_svg:
-
-      .. figure:: /images/opera_info_full.svg
-         :target: _images/opera_info_full.svg
-         :width: 100%
-         :align: center
-
-         The opera info testing on the `small TOSCA CSAR example <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/smal/small.csar>`_.
-
-   .. tab:: Details
-
-      With ``opera info`` user can get the information about the current opera
-      project and can access its storage and state. This included printing out
-      the path to TOSCA service template entrypoint, extracted CSAR location,
-      path to the storage inputs and status/state of the deployment. The output
-      can be formatted in YAML or JSON. The created json object looks like this:
-
-      .. code-block:: json
-
-         {
-         "service_template":  "string | null",
-         "content_root":      "string | null",
-         "inputs":            "string | null",
-         "status":            "initialized | deployed | undeployed | interrupted | null"
-         }
-
-
-package
-#######
-
-
-**Name**
-
-``package`` create compressed CSAR from the service template represeted with YAML-s.
-
-**Usage**
-
-      .. argparse::
-         :filename: src/opera/cli.py
-         :func: create_parser
-         :prog: opera
-         :path: package
-
-.. tabs::
-
-   .. tab:: Example
-
-      A minimal ``opera package`` example is shown on the image below
-      (:numref:`opera_package_minimal_svg`). The CSAR is created without any
-      optional params and current folder (.) is passed as a source dir. Opera
-      then looks for the root level yaml (``service.yaml``) and takes it as
-      the entrypoint for ``TOSCA.meta`` (``Entry-Definitions`` YAML keyname).
-      Since the output is not specified a random UUID (with the length of 6
-      chars) is created and the default zip format is used for the compression.
-      The example also has another scenario which features creating a CSAR
-      tarball (``tar`` compression format is specified using the
-      ``--format/-f`` CLI switch).
-
-      .. _opera_package_minimal_svg:
-
-      .. figure:: /images/opera_package_minimal.svg
-         :target: _images/opera_package_minimal.svg
-         :width: 100%
-         :align: center
-
-         Testing opera package on `intrinsic_functions <https://github.com/xlab-si/xopera-opera/tree/master/examples/intrinsic_functions>`_ and `policy_triggers <https://github.com/xlab-si/xopera-opera/tree/master/examples/policy_triggers>`_ example.
-
-      A more complex example (:numref:`opera_package_full_svg`) is below and
-      shows usage of packaging command with additional CLI flags. First a
-      zipped CSAR is created from already prepared extracted CSAR structure.
-      This CSAR is then validated with ``opera validate`` to show that the
-      created CSAR structure is deployable by the opera orchestrator. The
-      second part shows the creation of tar compressed TOSCA CSAR. The flags
-      ``--service-template/-t``, ``--output/-o`` and ``--format/-f`` are used
-      both times.
-
-      .. _opera_package_full_svg:
-
-      .. figure:: /images/opera_package_full.svg
-         :target: _images/opera_package_full.svg
-         :width: 100%
-         :align: center
-
-         Running opera package on the `opera integration tests CSAR examples <https://github.com/xlab-si/xopera-opera/tree/master/tests/integration>`_.
-
-
-   .. tab:: Details
-
-      The ``opera package`` command is used to create a valid TOSCA CSAR - a
-      deployable zip (or tar) compressed archive file. TOSCA CSARs contain the
-      blueprint of the application that we want to deploy. The process includes
-      packaging together the TOSCA service template and all the accompanying
-      files.
-
-      In general, ``opera package`` receives a directory (where user's TOSCA
-      templates and other files are located) and produces a compressed
-      CSAR file. The command can create the CSAR if there is at least one
-      TOSCA YAML file in the input folder. If the CSAR structure is already
-      present (if `TOSCA-Metadata/TOSCA.meta` exists and all other TOSCA CSAR
-      constraints are satisfied) the CSAR is created without an additional
-      temporary directory. And if not, the files are copied to the tempdir,
-      where the CSAR structure is created and at the end the tempdir is
-      compressed. The input folder is the mandatory positional argument, but
-      there are also other command flags that can be used.
-
-
-unpackage
-##########
-
-**Name**
-
-``unpackage`` uncompress CSAR.
-
-**Usage**
-      .. argparse::
-         :filename: src/opera/cli.py
-         :func: create_parser
-         :prog: opera
-         :path: unpackage
-
-.. tabs::
-
-   .. tab:: Example
-
-      A minimal example of ``opera unpackage`` is shown on the image below
-      (:numref:`opera_unpackage_minimal_svg`). The CSAR is unpacked without any
-      of the available optional params. The CSAR format is automatically
-      detected and the radon dirname with UUID is created for the destionation
-      folder where the extracted files reside.
-
-      .. _opera_unpackage_minimal_svg:
-
-      .. figure:: /images/opera_unpackage_minimal.svg
-         :target: _images/opera_unpackage_minimal.svg
-         :width: 100%
-         :align: center
-
-         Testing opera unpackage on the `prepared small CSAR example <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/smal/small.csar>`_.
-
-      A more complex example (:numref:`opera_unpackage_full_svg`) is below and
-      shows usage of unpackaging command with additional CLI flags and in
-      combination with ``opera package`` command. Therefore, the zip CSAR file
-      is created first and is later unpacked to a specified location
-      (the ``--destionation/-d`` switch is used here). Then the original folder
-      that the CSAR was created from with ``upera pcakge`` is compared to the
-      extracted folder which is a result of ``opera unpackage``. The folders
-      are almost identical, whereas the latter contains `TOSCA-Metadata/TOSCA.meta`
-      file which is specific for the TOSCA CSARs.
-
-      .. _opera_unpackage_full_svg:
-
-      .. figure:: /images/opera_unpackage_full.svg
-         :target: _images/opera_unpackage_full.svg
-         :width: 100%
-         :align: center
-
-         Running opera unpackage on the `hello world example <https://github.com/xlab-si/xopera-opera/tree/master/examples/hello>`_.
-
-
-   .. tab:: Details
-
-      The ``opera unpackage`` has the opposite function of the ``opera package``
-      command. It  serves for unpacking (i.e. validating and extracting) the
-      compressed TOSCA CSAR files. The opera unpackage command receives a
-      compressed CSAR as a positional argument. It then validates and extracts
-      the CSAR to a given location.
-
-      There's no ``--format/-f`` option. Rather than that, the compressed file
-      format (that will be used to extract the CSAR) is determined
-      automatically. Currently, the compressed CSARs can be supplied in two
-      different compression formats - `zip` or `tar`.
-
-
-init (deprecated since 0.6.1)
-#############################
-
-      .. argparse::
-         :filename: src/opera/cli.py
-         :func: create_parser
-         :prog: opera
-         :path: init
-
-.. tabs::
-
-   .. tab:: Example
-
-      The image below (:numref:`opera_init_service_template_svg`) shows an
-      example of initializing the TOSCA service template and then deploying it.
-      To save the orchestration data we created a custom folder (using the
-      ``--instance-path/-p option``) instead of the default ``.opera``.
-
-      .. _opera_init_service_template_svg:
-
-      .. figure:: /images/opera_init_service_template.svg
-         :target: _images/opera_init_service_template.svg
-         :width: 100%
-         :align: center
-
-         Initialization and deployment of `artifacts example <https://github.com/xlab-si/xopera-opera/tree/master/examples/artifacts>`_.
-
-      Another example in the figure below (:numref:`opera_init_csar_svg`)
-      shows the initialization and deployment of the compressed TOSCA CSAR
-      along with its `JSON inputs <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/inputs.json>`_.
-
-      .. _opera_init_csar_svg:
-
-      .. figure:: /images/opera_init_csar.svg
-         :target: _images/opera_init_csar.svg
-         :width: 100%
-         :align: center
-
-         Initialization and deployment of `small CSAR example <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/small.csar>`_.
-
-
-   .. tab:: Details
-
-      The deprecated ``opera init`` command is used to initialize the
-      deployment. It either takes a TOSCA template file or a compressed (zipped
-      CSAR) file (and an optional YAML file with inputs).
-
-      When the compressed CSAR is provided to the ``opera init`` command it is
-      then validated to be sure that the CSAR is compliant with TOSCA.
-
-      After the initialization the following files and folders will be created
-      in your opera storage directory (by default that is ``.opera`` and can be
-      changed using the ``--instance-path`` flag):
-
-      - ``root_file`` file - contains the path to the service template or CSAR
-      - ``inputs`` file - JSON file with the supplied inputs
-      - ``csars`` folder contains the extracted copy of your CSAR (created only if you deployed the compressed TOSCA CSAR)
-
-      After running ``opera init`` you will be able to initiate the deployment
-      process using just the ``opera deploy`` command without any positional
-      arguments (however, you can still supply inputs or override TOSCA service
-      template/CSAR).
-
-      .. deprecated:: 0.6.1
-
-
-
-.. note::
-
-   The ``opera init`` command is deprecated and will probably be removed
-   within one of the next releases. Please use ``opera deploy`` to initialize
-   and deploy service templates or compressed CSARs.
-
-.. hint::
-
-   Every CLI command is equipped with ``--help/-h`` switch that displays the
-   information about it and its arguments, and with ``--verbose/-v`` switch
-   which turns on debug mode and prints out the orchestration parameters and
-   the results from the executed Ansible playbooks.
+.. _Opera CLI:
+
+******************
+xOpera CLI (opera)
+******************
+
+.. _Opera CLI install:
+
+=================
+Installation
+=================
+
+This section explains the installation of xOpera orchestrator.
+
+**Prerequisites**
+
+
+``opera`` requires python 3 and a virtual environment. In a typical modern
+Linux environment, we should already be set. In Ubuntu, however, we might need
+to run the following commands::
+
+  $ sudo apt update
+  $ sudo apt install -y python3-venv python3-wheel python-wheel-common
+
+**Install**
+
+
+xOpera is distributed as Python package that is regularly published on `PyPI <https://pypi.org/project/opera/>`_.
+So the simplest way to test ``opera`` is to install it into virtual environment::
+
+  $ mkdir ~/opera && cd ~/opera
+  $ python3 -m venv .venv && . .venv/bin/activate
+  (.venv) $ pip install opera
+
+
+====================================
+Secrets and Environment variables
+====================================
+
+
+
+You can use the following environment variables:
+
++-----------------------------------+--------------------------------+---------------------------+
+| Environment variable              | Description                    | Example value             |
++===================================+================================+===========================+
+| | ``OPERA_SSH_USER``              | | Username for the Ansible ssh | | ``ubuntu``              |
+| |                                 | | connection to a remote VM    | | (default is ``centos``) |
++-----------------------------------+--------------------------------+---------------------------+
+| | ``OPERA_SSH_IDENTITY_FILE``     | | Path to the file containing  | | ``~/.ssh/id_ed25519``   |
+| |                                 | | your private ssh key that    | |                         |
+| |                                 | | will be used for a           | |                         |
+| |                                 | | connection to a remote VM    | |                         |
++-----------------------------------+--------------------------------+---------------------------+
+| | ``OPERA_SSH_HOST_KEY_CHECKING`` | | Disable Ansible host key     | | ``false`` or ``f``      |
+| |                                 | | checking (not recommended)   | | (not case sensitive)    |
++-----------------------------------+--------------------------------+---------------------------+
+
+.. danger::
+
+   Be very careful with your orchestration secrets (such as SSH private keys,
+   cloud credentials, passwords ans so on) that are stored as opera inputs.
+   To avoid exposing them don't share the inputs file and the created opera
+   storage folder with anyone.
+
+.. tip::
+
+   If you have any problems have a look at the existing issues here: https://github.com/xlab-si/xopera-opera/issues
+   or open a new one yourself.
+
+
+
+.. _CLI Reference:
+
+==========================
+CLI reference and examples
+==========================
+
+``opera`` was  originally meant to be used in a terminal as a client and it
+currently allows users to execute the following commands:
+
++---------------------+----------------------------------------------+
+| CLI command         | Purpose and description                      |
++=====================+==============================================+
+| ``opera deploy``    | deploy TOSCA service template or CSAR        |
++---------------------+----------------------------------------------+
+| ``opera undeploy``  | undeploy TOSCA service template or CSAR      |
++---------------------+----------------------------------------------+
+| ``opera validate``  | validate TOSCA service template or CSAR      |
++---------------------+----------------------------------------------+
+| ``opera outputs``   | retrieve outputs from service template       |
++---------------------+----------------------------------------------+
+| ``opera info``      | show information about the current project   |
++---------------------+----------------------------------------------+
+| ``opera package``   | retrieve outputs from service template       |
++---------------------+----------------------------------------------+
+| ``opera unpackage`` | retrieve outputs from service template       |
++---------------------+----------------------------------------------+
+| ``opera init``      | initialize the service template or CSAR      |
++---------------------+----------------------------------------------+
+
+The commands can be executed in a random order and the orchestrator will warn and the orchestrator will warn you
+in case if any problems.
+Each CLI command is described more in detail in the following sections.
+
+
+deploy
+######
+
+**Name**
+
+``deploy`` - used to deploy and control deployment of the application described in YAML or CSAR.
+
+**Usage**
+
+      .. argparse::
+         :filename: src/opera/cli.py
+         :func: create_parser
+         :prog: opera
+         :path: deploy
+
+         The ``--resume/-r`` and ``--clean-state/-c`` options are mutually exclusive.
+
+
+.. tabs::
+
+   .. tab:: Example
+
+      A simple deployment of TOSCA service template is shown on the next image (:numref:`opera_deploy_service_template_svg`).
+
+      .. _opera_deploy_service_template_svg:
+
+      .. figure:: /images/opera_deploy_service_template.svg
+         :target: _images/opera_deploy_service_template.svg
+         :width: 100%
+         :align: center
+
+         Example of `hello world <https://github.com/xlab-si/xopera-opera/tree/master/examples/hello>`_ template opera deployment.
+
+      Another example (:numref:`opera_deploy_csar_svg`) is below and shows a more
+      complex usage of ``opera deploy`` command, deploying the compressed TOSCA
+      CSAR with inputs and additional CLI flags. The CSAR is first deployed with
+      the supplied `YAML inputs <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/inputs.yaml>`_
+      (using ``--inputs/-i`` flag) and with two workers (``--workers/-w`` switch)
+      that can run two Ansible playbook operations simultaneously. Then the CSAR
+      is deployed again (using the ``--clean-state/-c`` option) from the beginning,
+      but the execution gets interrupted. Therefore the third deployment is used
+      to resume the deployment process from where it was interrupted (using the
+      ``--resume/-r`` flag, we also used ``--force/-f`` flag here to skip all
+      yes/no prompts).
+
+      .. _opera_deploy_csar_svg:
+
+      .. figure:: /images/opera_deploy_csar.svg
+         :target: _images/opera_deploy_csar.svg
+         :width: 100%
+         :align: center
+
+         The `big CSAR <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/big.csar>`_ example deployment.
+
+   .. tab:: Source
+
+      CLI instructions for example
+
+      .. code-block:: bash
+
+         cd xopera-opera/examples/hello
+         opera deploy service.yaml
+         opera undeploy
+
+      .. hint::
+         Instead of ``service.yaml`` you can deploy a compressed TOSCA CSAR directly with ``deploy`` command.
+
+
+
+
+   .. tab:: Details
+
+      The ``opera deploy`` command is used to initiate the deployment
+      orchestration process using the supplied TOSCA service template or the
+      compressed TOSCA CSAR. Within this CLI command the xOpera orchestrator
+      invokes multiple `TOSCA interface operations <https://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.3/cos01/TOSCA-Simple-Profile-YAML-v1.3-cos01.html#_Toc26969470>`_
+      (TOSCA `Standard interface` node operations and also TOSCA `Configure interface`
+      relationship operations). The operations are executed in the following order:
+
+      1. ``create``
+      2. ``pre_configure_source``
+      3. ``pre_configure_target``
+      4. ``configure``
+      5. ``post_configure_source``
+      6. ``post_configure_target``
+      7. ``start``
+
+      The operation gets executed if it is defined within the TOSCA service template
+      and has a link to the corresponding Ansible playbook.
+
+      After the deployment the following files and folders will be created in
+      your opera storage directory (by default that is ``.opera`` and can be
+      changed using the ``--instance-path`` flag):
+
+      - ``root_file`` file - contains the path to the service template or CSAR
+      - ``inputs`` file - JSON file with the supplied inputs
+      - ``instances`` folder - includes JSON files that carry the information about the status of TOSCA node and relationship instances
+      - ``csars`` folder contains the extracted copy of your CSAR (created only if you deployed the compressed TOSCA CSAR)
+
+
+
+
+
+
+undeploy
+#########
+
+**Name**
+
+
+``undeploy`` - undeploys application; removes all application instances and components.
+
+**Usage**
+
+      .. argparse::
+         :filename: src/opera/cli.py
+         :func: create_parser
+         :prog: opera
+         :path: undeploy
+
+         The ``opera undeploy`` command does not take any positional arguments.
+
+
+.. tabs::
+
+   .. tab:: Example
+
+      A simple undeployment process of TOSCA service template is shown on the
+      next image (:numref:`opera_undeploy_svg`). The service template should
+      be deployed first and the you can undeploy the solution.
+
+      .. _opera_undeploy_svg:
+
+      .. figure:: /images/opera_cli.svg
+         :target: _images/opera_cli.svg
+         :width: 100%
+         :align: center
+
+         Example showing `hello <https://github.com/xlab-si/xopera-opera/tree/master/examples/hello>`_ template opera undeployment.
+
+      Another example (:numref:`opera_undeploy_csar_svg`) is below and shows a more
+      complex usage of ``opera undeploy`` command, undeploying the compressed TOSCA
+      CSAR with additional CLI flags. The CSAR was first deployed with the supplied
+      `inputs file <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/inputs.yaml>`_
+      Then the CSAR is undeployed, but the execution gets interrupted. To resume
+      the undeployment process from where it was interrupted the ``--resume/-r``
+      flag is used.
+
+      .. _opera_undeploy_csar_svg:
+
+      .. figure:: /images/opera_undeploy_csar.svg
+         :target: _images/opera_undeploy_csar.svg
+         :width: 100%
+         :align: center
+
+         The undeployment of the `big CSAR example <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/big.csar>`_.
+
+   .. tab:: Source
+
+      CLI instructions for example
+
+      .. code-block:: bash
+
+         cd xopera-opera/examples/hello
+         opera deploy service.yaml
+         opera undeploy
+         # If undeploy was interrupted
+         opera undeploy -r
+
+      .. hint::
+         Instead of ``service.yaml`` you can deploy a compressed TOSCA CSAR directly with ``deploy`` command.
+
+
+   .. tab:: Details
+
+      The ``opera undeploy`` command is used to tear down the deployed blueprint.
+      Within the undeployment process the xOpera orchestrator invokes two TOSCA
+      Standard interface node operations in the following order:
+
+      1. ``stop``
+      2. ``delete``
+
+      The operation gets executed if it is defined within the TOSCA service template
+      and has a link to the corresponding Ansible playbook.
+
+
+
+validate
+########
+
+**Name**
+
+Validates the structure of TOSCA template or CSAR
+
+**Usage**
+      .. argparse::
+         :filename: src/opera/cli.py
+         :func: create_parser
+         :prog: opera
+         :path: validate
+
+
+.. tabs::
+
+   .. tab:: Example
+
+      The first image below (:numref:`opera_validate_service_template_svg`) shows an example of
+      TOSCA service template validation.
+
+      .. _opera_validate_service_template_svg:
+
+      .. figure:: /images/opera_validate_service_template.svg
+         :target: _images/opera_validate_service_template.svg
+         :width: 100%
+         :align: center
+
+         Example showing `attribute mapping <https://github.com/xlab-si/xopera-opera/tree/master/examples/attribute_mapping>`_ template validation.
+
+      The second image (:numref:`opera_validate_csar_svg`) shows an example of
+      TOSCA zipped CSAR validation where orchestration YAML inputs file is also supplied.
+
+      .. _opera_validate_csar_svg:
+
+      .. figure:: /images/opera_validate_csar.svg
+         :target: _images/opera_validate_csar.svg
+         :width: 100%
+         :align: center
+
+         Example showing `big <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/big/big.csar>`_ CSAR validation.
+
+   .. tab:: Source
+
+      CLI instructions for example
+
+      .. code-block:: bash
+
+         cd xopera-opera/examples/attribute_mapping
+         opera validate service yaml
+
+         opera validate -i inputs.yaml big.csar
+
+      .. hint::
+         Instead of ``service.yaml`` you can deploy a compressed TOSCA CSAR directly with ``deploy`` command.
+
+
+   .. tab:: Overview
+
+      With ``opera validate`` you can validate any TOSCA template or CSAR and
+      find out whether it's properly structured and deployable by opera. At the
+      end of this operation you will receive the validation result where opera
+      will warn you about TOSCA template inconsistencies if there was any.
+
+
+outputs
+#######
+
+
+**Name**
+
+``outputs`` Print the outputs of the deploy/undeploy.
+
+**Usage**
+
+
+      .. argparse::
+         :filename: src/opera/cli.py
+         :func: create_parser
+         :prog: opera
+         :path: outputs
+
+.. tabs::
+
+   .. tab:: Example
+
+      The image below (:numref:`opera_outputs_service_template_svg`) shows an
+      example of retrieving the orchestration outputs after the deployment process.
+
+      .. _opera_outputs_service_template_svg:
+
+      .. figure:: /images/opera_outputs_service_template.svg
+         :target: _images/opera_outputs_service_template.svg
+         :width: 100%
+         :align: center
+
+         Example showing `orchestration outputs <https://github.com/xlab-si/xopera-opera/tree/master/examples/outputs>`_ retrieval.
+
+      Another example in the figure below (:numref:`opera_outputs_csar_svg`)
+      shows deploying the TOSCA CSAR with the supplied
+      `JSON inputs file <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/inputs.json>`_.
+      After that the outputs are retrieved and formatted in JSON (using ``--format/-f`` option).
+
+      .. _opera_outputs_csar_svg:
+
+      .. figure:: /images/opera_outputs_csar.svg
+         :target: _images/opera_outputs_csar.svg
+         :width: 100%
+         :align: center
+
+         Example showing `small CSAR <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/small.csar>`_ deployment and outputs retrieval.
+
+   .. tab:: Details
+
+      The ``opera outputs`` command lets you access the orchestration outputs
+      defined in the TOSCA service template and print them out to the console
+      in JSON or YAML format.
+
+
+
+
+info
+#######
+
+**Name**
+
+``info`` - print the details of current deployment project
+
+**Usage**
+
+      .. argparse::
+         :filename: src/opera/cli.py
+         :func: create_parser
+         :prog: opera
+         :path: info
+
+
+.. tabs::
+
+   .. tab:: Example
+
+      A minimal ``opera info`` example is shown on the image below (:numref:`opera_info_minimal_svg`).
+      The service template is deployed first with the debug mode turned on
+      (``--verbose/-v`` flag is used, which prints out the inputs and the
+      Ansible playbook tasks outputs). Then ``opera info`` command is used to
+      print out the information about the current opera project.
+
+      .. _opera_info_minimal_svg:
+
+      .. figure:: /images/opera_info_minimal.svg
+         :target: _images/opera_info_minimal.svg
+         :width: 100%
+         :align: center
+
+         Testing opera info on the `capability_attributes_properties example <https://github.com/xlab-si/xopera-opera/tree/master/examples/capability_attributes_properties>`_.
+
+      A more complex example (:numref:`opera_info_full_svg`) is below and shows a
+      combined usage of init, deploy and undeploy commands on the zipped TOSCA
+      CSAR with additional CLI flags. After every operation ``opera info`` CLI
+      command is called to explore the current status of the project.
+
+      The CSAR was first initialized without the inputs. Those (in `inputs.json file <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/inputs.json>`_)
+      were supplied within the second deployment step, which gets interrupted
+      and this affects the current project state. To resume the deployment
+      process from where it was interrupted the ``--resume/-r`` flag is used.
+      Then the CSAR is undeployed. The ``opera info`` output is printed
+      out in both YAML and JSON formats (here ``--format/-f`` is used).
+
+      .. _opera_info_full_svg:
+
+      .. figure:: /images/opera_info_full.svg
+         :target: _images/opera_info_full.svg
+         :width: 100%
+         :align: center
+
+         The opera info testing on the `small TOSCA CSAR example <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/smal/small.csar>`_.
+
+   .. tab:: Details
+
+      With ``opera info`` user can get the information about the current opera
+      project and can access its storage and state. This included printing out
+      the path to TOSCA service template entrypoint, extracted CSAR location,
+      path to the storage inputs and status/state of the deployment. The output
+      can be formatted in YAML or JSON. The created json object looks like this:
+
+      .. code-block:: json
+
+         {
+         "service_template":  "string | null",
+         "content_root":      "string | null",
+         "inputs":            "string | null",
+         "status":            "initialized | deployed | undeployed | interrupted | null"
+         }
+
+
+package
+#######
+
+
+**Name**
+
+``package`` create compressed CSAR from the service template represeted with YAML-s.
+
+**Usage**
+
+      .. argparse::
+         :filename: src/opera/cli.py
+         :func: create_parser
+         :prog: opera
+         :path: package
+
+.. tabs::
+
+   .. tab:: Example
+
+      A minimal ``opera package`` example is shown on the image below
+      (:numref:`opera_package_minimal_svg`). The CSAR is created without any
+      optional params and current folder (.) is passed as a source dir. Opera
+      then looks for the root level yaml (``service.yaml``) and takes it as
+      the entrypoint for ``TOSCA.meta`` (``Entry-Definitions`` YAML keyname).
+      Since the output is not specified a random UUID (with the length of 6
+      chars) is created and the default zip format is used for the compression.
+      The example also has another scenario which features creating a CSAR
+      tarball (``tar`` compression format is specified using the
+      ``--format/-f`` CLI switch).
+
+      .. _opera_package_minimal_svg:
+
+      .. figure:: /images/opera_package_minimal.svg
+         :target: _images/opera_package_minimal.svg
+         :width: 100%
+         :align: center
+
+         Testing opera package on `intrinsic_functions <https://github.com/xlab-si/xopera-opera/tree/master/examples/intrinsic_functions>`_ and `policy_triggers <https://github.com/xlab-si/xopera-opera/tree/master/examples/policy_triggers>`_ example.
+
+      A more complex example (:numref:`opera_package_full_svg`) is below and
+      shows usage of packaging command with additional CLI flags. First a
+      zipped CSAR is created from already prepared extracted CSAR structure.
+      This CSAR is then validated with ``opera validate`` to show that the
+      created CSAR structure is deployable by the opera orchestrator. The
+      second part shows the creation of tar compressed TOSCA CSAR. The flags
+      ``--service-template/-t``, ``--output/-o`` and ``--format/-f`` are used
+      both times.
+
+      .. _opera_package_full_svg:
+
+      .. figure:: /images/opera_package_full.svg
+         :target: _images/opera_package_full.svg
+         :width: 100%
+         :align: center
+
+         Running opera package on the `opera integration tests CSAR examples <https://github.com/xlab-si/xopera-opera/tree/master/tests/integration>`_.
+
+
+   .. tab:: Details
+
+      The ``opera package`` command is used to create a valid TOSCA CSAR - a
+      deployable zip (or tar) compressed archive file. TOSCA CSARs contain the
+      blueprint of the application that we want to deploy. The process includes
+      packaging together the TOSCA service template and all the accompanying
+      files.
+
+      In general, ``opera package`` receives a directory (where user's TOSCA
+      templates and other files are located) and produces a compressed
+      CSAR file. The command can create the CSAR if there is at least one
+      TOSCA YAML file in the input folder. If the CSAR structure is already
+      present (if `TOSCA-Metadata/TOSCA.meta` exists and all other TOSCA CSAR
+      constraints are satisfied) the CSAR is created without an additional
+      temporary directory. And if not, the files are copied to the tempdir,
+      where the CSAR structure is created and at the end the tempdir is
+      compressed. The input folder is the mandatory positional argument, but
+      there are also other command flags that can be used.
+
+
+unpackage
+##########
+
+**Name**
+
+``unpackage`` uncompress CSAR.
+
+**Usage**
+      .. argparse::
+         :filename: src/opera/cli.py
+         :func: create_parser
+         :prog: opera
+         :path: unpackage
+
+.. tabs::
+
+   .. tab:: Example
+
+      A minimal example of ``opera unpackage`` is shown on the image below
+      (:numref:`opera_unpackage_minimal_svg`). The CSAR is unpacked without any
+      of the available optional params. The CSAR format is automatically
+      detected and the radon dirname with UUID is created for the destionation
+      folder where the extracted files reside.
+
+      .. _opera_unpackage_minimal_svg:
+
+      .. figure:: /images/opera_unpackage_minimal.svg
+         :target: _images/opera_unpackage_minimal.svg
+         :width: 100%
+         :align: center
+
+         Testing opera unpackage on the `prepared small CSAR example <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/smal/small.csar>`_.
+
+      A more complex example (:numref:`opera_unpackage_full_svg`) is below and
+      shows usage of unpackaging command with additional CLI flags and in
+      combination with ``opera package`` command. Therefore, the zip CSAR file
+      is created first and is later unpacked to a specified location
+      (the ``--destionation/-d`` switch is used here). Then the original folder
+      that the CSAR was created from with ``upera pcakge`` is compared to the
+      extracted folder which is a result of ``opera unpackage``. The folders
+      are almost identical, whereas the latter contains `TOSCA-Metadata/TOSCA.meta`
+      file which is specific for the TOSCA CSARs.
+
+      .. _opera_unpackage_full_svg:
+
+      .. figure:: /images/opera_unpackage_full.svg
+         :target: _images/opera_unpackage_full.svg
+         :width: 100%
+         :align: center
+
+         Running opera unpackage on the `hello world example <https://github.com/xlab-si/xopera-opera/tree/master/examples/hello>`_.
+
+
+   .. tab:: Details
+
+      The ``opera unpackage`` has the opposite function of the ``opera package``
+      command. It  serves for unpacking (i.e. validating and extracting) the
+      compressed TOSCA CSAR files. The opera unpackage command receives a
+      compressed CSAR as a positional argument. It then validates and extracts
+      the CSAR to a given location.
+
+      There's no ``--format/-f`` option. Rather than that, the compressed file
+      format (that will be used to extract the CSAR) is determined
+      automatically. Currently, the compressed CSARs can be supplied in two
+      different compression formats - `zip` or `tar`.
+
+
+init (deprecated since 0.6.1)
+#############################
+
+      .. argparse::
+         :filename: src/opera/cli.py
+         :func: create_parser
+         :prog: opera
+         :path: init
+
+.. tabs::
+
+   .. tab:: Example
+
+      The image below (:numref:`opera_init_service_template_svg`) shows an
+      example of initializing the TOSCA service template and then deploying it.
+      To save the orchestration data we created a custom folder (using the
+      ``--instance-path/-p option``) instead of the default ``.opera``.
+
+      .. _opera_init_service_template_svg:
+
+      .. figure:: /images/opera_init_service_template.svg
+         :target: _images/opera_init_service_template.svg
+         :width: 100%
+         :align: center
+
+         Initialization and deployment of `artifacts example <https://github.com/xlab-si/xopera-opera/tree/master/examples/artifacts>`_.
+
+      Another example in the figure below (:numref:`opera_init_csar_svg`)
+      shows the initialization and deployment of the compressed TOSCA CSAR
+      along with its `JSON inputs <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/inputs.json>`_.
+
+      .. _opera_init_csar_svg:
+
+      .. figure:: /images/opera_init_csar.svg
+         :target: _images/opera_init_csar.svg
+         :width: 100%
+         :align: center
+
+         Initialization and deployment of `small CSAR example <https://github.com/xlab-si/xopera-opera/tree/master/docs/files/csars/small/small.csar>`_.
+
+
+   .. tab:: Details
+
+      The deprecated ``opera init`` command is used to initialize the
+      deployment. It either takes a TOSCA template file or a compressed (zipped
+      CSAR) file (and an optional YAML file with inputs).
+
+      When the compressed CSAR is provided to the ``opera init`` command it is
+      then validated to be sure that the CSAR is compliant with TOSCA.
+
+      After the initialization the following files and folders will be created
+      in your opera storage directory (by default that is ``.opera`` and can be
+      changed using the ``--instance-path`` flag):
+
+      - ``root_file`` file - contains the path to the service template or CSAR
+      - ``inputs`` file - JSON file with the supplied inputs
+      - ``csars`` folder contains the extracted copy of your CSAR (created only if you deployed the compressed TOSCA CSAR)
+
+      After running ``opera init`` you will be able to initiate the deployment
+      process using just the ``opera deploy`` command without any positional
+      arguments (however, you can still supply inputs or override TOSCA service
+      template/CSAR).
+
+      .. deprecated:: 0.6.1
+
+
+
+.. note::
+
+   The ``opera init`` command is deprecated and will probably be removed
+   within one of the next releases. Please use ``opera deploy`` to initialize
+   and deploy service templates or compressed CSARs.
+
+.. hint::
+
+   Every CLI command is equipped with ``--help/-h`` switch that displays the
+   information about it and its arguments, and with ``--verbose/-v`` switch
+   which turns on debug mode and prints out the orchestration parameters and
+   the results from the executed Ansible playbooks.
diff --git a/docs/quickstart.rst b/docs/quickstart.rst
index 1ffc9c65..8e478922 100755
--- a/docs/quickstart.rst
+++ b/docs/quickstart.rst
@@ -1,120 +1,122 @@
-.. _Quickstart:
-
-*******************
-Quickstart
-*******************
-
-======================
-Opera CLI Quickstart 
-======================
-
-
-After you `installed xOpera CLI <Opera CLI install>`_ into virtual environment you can test if everything is working as expected. We can now try to
-deploy an example `hello-world service <https://github.com/xlab-si/xopera-opera/tree/master/examples/hello>`_ that is
-accessible on GitHub.::
-
-  (.venv) $ git clone git@github.com:xlab-si/xopera-opera.git
-  (.venv) $ cd examples/hello
-  (.venv) $ opera deploy service.yaml
-
-If nothing went wrong, new empty file has been created at ``/tmp/playing-opera/hello/hello.txt``.
-
-To delete the created directory, we can undeploy our stuff by running::
-
-   (.venv) $ opera undeploy
-
-
-If you want to try out one fast and easy xOpera example you can copy the hello world service template below.
-
-.. code-block:: yaml
-
-    ---
-    tosca_definitions_version: tosca_simple_yaml_1_3
-
-    node_types:
-      hello_type:
-        derived_from: tosca.nodes.SoftwareComponent
-        interfaces:
-          Standard:
-            inputs:
-              content:
-                default: { get_input: content }
-                type: string
-            operations:
-              create: playbooks/create.yml
-              delete: playbooks/delete.yml
-
-    topology_template:
-      inputs:
-        content:
-          type: string
-          default: "Hello from Ansible and xOpera!\n"
-
-      node_templates:
-        my-workstation:
-          type: tosca.nodes.Compute
-          attributes:
-            private_address: localhost
-            public_address: localhost
-
-        hello:
-          type: hello_type
-          requirements:
-            - host: my-workstation
-    ...
-
-As you can see it is has only one node type defined. This `hello_type` here has two linked implementations that are actually
-two TOSCA operations (create and delete) that are implemented in a form of Ansible playbooks. The Ansible playbook for
-creation is shown below and it is used to create a new folder and hello world file in `/tmp` directory.
-
-.. code-block:: yaml
-
-    ---
-    - hosts: all
-      gather_facts: false
-
-      tasks:
-        - name: Create the new folder structure
-          file:
-            path: /tmp/opera-test/hello
-            recurse: true
-            state: directory
-
-        - name: Create hello.txt and add content
-          copy:
-            dest: /tmp/opera-test/hello/hello.txt
-            content: "{{ content }}"
-    ...
-
-And the playbook for destroying the service is below.
-
-.. code-block:: yaml
-
-    ---
-    - hosts: all
-      gather_facts: false
-
-      tasks:
-        - name: Remove the location
-          file:
-            path: /tmp/opera-test
-            state: absent
-    ...
-
-You can initiate xOpera orchestration service with ``opera deploy tosca-template.yml`` in order to start the deployment
-and then also ``opera undeploy`` to un-deploy the solution (see image below :ref:`opera_deploy_cli`).
-
-.. _opera_deploy_cli:
-
-.. figure:: /images/opera_deploy_cli.png
-    :target: _images/opera_deploy_cli.png
-    :width: 80%
-    :align: center
-
-    xOpera CLI deployment
-
-
-======================
-xOpera SaaS Quickstart 
-======================
-
+.. _Quickstart:
+
+**********
+Quickstart
+**********
+
+====================
+Opera CLI Quickstart
+====================
+
+
+After you `installed xOpera CLI <Opera CLI install>`_ into virtual environment you can test if everything is working as expected. We can now try to
+deploy an example `hello-world service <https://github.com/xlab-si/xopera-opera/tree/master/examples/hello>`_ that is
+accessible on GitHub.::
+
+  (.venv) $ git clone git@github.com:xlab-si/xopera-opera.git
+  (.venv) $ cd examples/hello
+  (.venv) $ opera deploy service.yaml
+
+If nothing went wrong, new empty file has been created at ``/tmp/playing-opera/hello/hello.txt``.
+
+To delete the created directory, we can undeploy our stuff by running::
+
+   (.venv) $ opera undeploy
+
+
+If you want to try out one fast and easy xOpera example you can copy the hello world service template below.
+
+.. code-block:: yaml
+
+    ---
+    tosca_definitions_version: tosca_simple_yaml_1_3
+
+    node_types:
+      hello_type:
+        derived_from: tosca.nodes.SoftwareComponent
+        interfaces:
+          Standard:
+            inputs:
+              content:
+                default: { get_input: content }
+                type: string
+            operations:
+              create: playbooks/create.yml
+              delete: playbooks/delete.yml
+
+    topology_template:
+      inputs:
+        content:
+          type: string
+          default: "Hello from Ansible and xOpera!\n"
+
+      node_templates:
+        my-workstation:
+          type: tosca.nodes.Compute
+          attributes:
+            private_address: localhost
+            public_address: localhost
+
+        hello:
+          type: hello_type
+          requirements:
+            - host: my-workstation
+    ...
+
+As you can see it is has only one node type defined.
+This `hello_type` here has two linked implementations that are actually two TOSCA operations (create and delete) that
+are implemented in a form of Ansible playbooks.
+The Ansible playbook for creation is shown below and it is used to create a new folder and hello world file
+in `/tmp` directory.
+
+.. code-block:: yaml
+
+    ---
+    - hosts: all
+      gather_facts: false
+
+      tasks:
+        - name: Create the new folder structure
+          file:
+            path: /tmp/opera-test/hello
+            recurse: true
+            state: directory
+
+        - name: Create hello.txt and add content
+          copy:
+            dest: /tmp/opera-test/hello/hello.txt
+            content: "{{ content }}"
+    ...
+
+And the playbook for destroying the service is below.
+
+.. code-block:: yaml
+
+    ---
+    - hosts: all
+      gather_facts: false
+
+      tasks:
+        - name: Remove the location
+          file:
+            path: /tmp/opera-test
+            state: absent
+    ...
+
+You can initiate xOpera orchestration service with ``opera deploy tosca-template.yml`` in order to start the deployment
+and then also ``opera undeploy`` to un-deploy the solution (see image below :ref:`opera_deploy_cli`).
+
+.. _opera_deploy_cli:
+
+.. figure:: /images/opera_deploy_cli.png
+    :target: _images/opera_deploy_cli.png
+    :width: 80%
+    :align: center
+
+    xOpera CLI deployment
+
+
+======================
+xOpera SaaS Quickstart
+======================
+
diff --git a/docs/template_library.rst b/docs/template_library.rst
index 0239536b..adbfe5cd 100755
--- a/docs/template_library.rst
+++ b/docs/template_library.rst
@@ -4,7 +4,8 @@
 xOpera TPS (template library)
 *****************************
 
-xOpera TPS is a TOSCA Template Publishing service `available online <https://template-library-radon.xlab.si>`_. It includes templates of TOSCA service templates in form of CSARs and TOSCA artefacts to build applications. 
+xOpera TPS is a TOSCA Template Publishing service `available online <https://template-library-radon.xlab.si>`_.
+It includes templates of TOSCA service templates in form of CSARs and TOSCA artefacts to build applications.
 
 More details available at the `TPS Documentation page <https://template-library-radon.xlab.si/docs>`_.
 
diff --git a/examples/artifacts/files/file.json b/examples/artifacts/files/file.json
index 183ec96c..44bfe67a 100644
--- a/examples/artifacts/files/file.json
+++ b/examples/artifacts/files/file.json
@@ -1,3 +1,3 @@
 {
-  "content": "This is an example JSON file content."
+    "content": "This is an example JSON file content."
 }
diff --git a/examples/artifacts/service.yaml b/examples/artifacts/service.yaml
index ef302aeb..22806fc5 100644
--- a/examples/artifacts/service.yaml
+++ b/examples/artifacts/service.yaml
@@ -30,9 +30,9 @@ node_types:
                 type: string
                 default: { get_property: [ SELF, json_file ] }
     artifacts:
-        text_file:
-          type: tosca.artifacts.File
-          file: files/file.txt
+      text_file:
+        type: tosca.artifacts.File
+        file: files/file.txt
 
 topology_template:
   node_templates:
@@ -41,9 +41,9 @@ topology_template:
       properties:
         json_file: { get_artifact: [ SELF, json_file ] }
       artifacts:
-          json_file:
-            type: tosca.artifacts.File
-            file: files/file.json
+        json_file:
+          type: tosca.artifacts.File
+          file: files/file.json
 
   outputs:
     output_attribute_text_file:
diff --git a/examples/intrinsic_functions/service.yaml b/examples/intrinsic_functions/service.yaml
index 6499d0d7..5be491e8 100644
--- a/examples/intrinsic_functions/service.yaml
+++ b/examples/intrinsic_functions/service.yaml
@@ -80,29 +80,29 @@ topology_template:
       # Result: http://attribute1:property1
       description: Concatenate string values
       value: { concat: [ 'http://',
-                       get_attribute: [ hello1, attribute1 ],
-                       ':',
-                       get_property: [ hello1, property1 ] ] }
+                         get_attribute: [ hello1, attribute1 ],
+                         ':',
+                         get_property: [ hello1, property1 ] ] }
     join1_output:
-       # Result: tosca
+      # Result: tosca
       description: Join string values without a delimiter (concat)
       value: { join: [ [ "t", "o", "s", "c", "a" ] ] }
     join2_output:
-       # Result: t_o_s_c_a
+      # Result: t_o_s_c_a
       description: Join string values with delimiter
       value: { join: [ [ "t", "o", "s", "c", "a" ], "_" ] }
     join3_output:
-       # Result: input, attribute2, property2
+      # Result: input, attribute2, property2
       description: Join string values with delimiter
       value: { join: [ [ { get_input: input },
                          { get_attribute: [ hello2, attribute2 ] },
                          { get_property: [ hello2, property2 ] } ], ", " ] }
     token1_output:
-       # Result: 111
+      # Result: 111
       description: Tokenize the string and get the zeroth substring
       value: { token: [ "111 222 333 444", " ", 0 ] }
     token2_output:
-       # Result: s
+      # Result: s
       description: Tokenize the string and get the second substring
       value: { token: [ "t-*-o-*-s-*-c-*-a", "-*-", 2 ] }
     attribute:
@@ -117,5 +117,5 @@ topology_template:
       # Result: Properties: property1 property2 property
       description: Joined properties
       value: { join: [[ 'Properties:', { get_property: [ hello1, property1 ] },
-                                        { get_property: [ hello2, property2 ] },
-                                        { get_property: [ hello3, property3_1 ] } ], " " ] }
+                        { get_property: [ hello2, property2 ] },
+                        { get_property: [ hello3, property3_1 ] } ], " " ] }
diff --git a/examples/policy_triggers/service.yaml b/examples/policy_triggers/service.yaml
index a131c564..1f65653f 100644
--- a/examples/policy_triggers/service.yaml
+++ b/examples/policy_triggers/service.yaml
@@ -82,9 +82,9 @@ policy_types:
           node: radon.nodes.OpenStack.VM
         condition:
           - not:
-            - and:
-              - available_instances: [ { greater_than: 42 } ]
-              - available_space: [ { greater_than: 1000 } ]
+              - and:
+                  - available_instances: [ { greater_than: 42 } ]
+                  - available_space: [ { greater_than: 1000 } ]
         action:
           - call_operation:
               operation: radon.interfaces.scaling.ScaleDown.scale_down
@@ -115,9 +115,9 @@ policy_types:
           node: radon.nodes.OpenStack.VM
         condition:
           - not:
-            - and:
-              - available_instances: [ { greater_than: 42 } ]
-              - available_space: [ { greater_than: 1000 } ]
+              - and:
+                  - available_instances: [ { greater_than: 42 } ]
+                  - available_space: [ { greater_than: 1000 } ]
         action:
           - call_operation:
               operation: radon.interfaces.scaling.ScaleUp.scale_up
@@ -194,9 +194,9 @@ topology_template:
             condition:
               constraint:
                 - not:
-                  - and:
-                    - available_instances: [ { greater_than: 42 } ]
-                    - available_space: [ { greater_than: 1000 } ]
+                    - and:
+                        - available_instances: [ { greater_than: 42 } ]
+                        - available_space: [ { greater_than: 1000 } ]
               period: 60 sec
               evaluations: 2
               method: average
diff --git a/examples/runme.sh b/examples/runme.sh
index 8b2c0a1b..a301c117 100755
--- a/examples/runme.sh
+++ b/examples/runme.sh
@@ -57,4 +57,4 @@ $opera_executable outputs -p relationship_outputs/.opera
 echo "All tests have finished successfully."
 
 # an end-to-end example from ./nginx_openstack cannot be deployed directly
-# with CI/CD because it requires special resources
\ No newline at end of file
+# with CI/CD because it requires special resources
diff --git a/src/opera/cli.py b/src/opera/cli.py
index 57ec6b4c..67606ae9 100644
--- a/src/opera/cli.py
+++ b/src/opera/cli.py
@@ -1,24 +1,23 @@
 import argparse
 import inspect
 import sys
+
 import shtab
 
 from opera import commands
 
 
 class ArgParser(argparse.ArgumentParser):
-    """
-    Argument parser that displays help on error
-    """
+    """An argument parser that displays help on error."""
 
     def error(self, message):
         sys.stderr.write("error: {}\n".format(message))
         self.print_help()
         sys.exit(2)
 
-    def add_subparsers(self):
+    def add_subparsers(self, **kwargs):
         # Workaround for http://bugs.python.org/issue9253
-        subparsers = super(ArgParser, self).add_subparsers()
+        subparsers = super(ArgParser, self).add_subparsers()  # pylint: disable=super-with-arguments
         subparsers.required = True
         subparsers.dest = "command"
         return subparsers
@@ -40,8 +39,9 @@ def main():
     parser = create_parser()
     # use shtab magic
     # add global optional argument for generating shell completion script
-    shtab.add_argument_to(parser, ["-s", "--shell-completion"],
-                          help="Generate tab completion script for your shell"
-                          )
+    shtab.add_argument_to(
+        parser, ["-s", "--shell-completion"],
+        help="Generate tab completion script for your shell"
+    )
     args = parser.parse_args()
     return args.func(args)
diff --git a/src/opera/commands/__init__.py b/src/opera/commands/__init__.py
index d2b131c8..719990d4 100644
--- a/src/opera/commands/__init__.py
+++ b/src/opera/commands/__init__.py
@@ -1,4 +1,4 @@
-from opera.commands import (
+from opera.commands import (  # noqa: F401
     deploy,
     diff,
     info,
diff --git a/src/opera/commands/deploy.py b/src/opera/commands/deploy.py
index a62e0592..7c754e7b 100644
--- a/src/opera/commands/deploy.py
+++ b/src/opera/commands/deploy.py
@@ -1,18 +1,19 @@
 import argparse
 import typing
-import yaml
-import shtab
-
 from os import path
 from pathlib import Path, PurePath
 from zipfile import ZipFile, is_zipfile
 
+import shtab
+import yaml
+from yaml import YAMLError
+
 from opera.commands.info import info
-from opera.utils import prompt_yes_no_question
 from opera.error import DataError, ParseError
 from opera.parser import tosca
 from opera.parser.tosca.csar import CloudServiceArchive
 from opera.storage import Storage
+from opera.utils import prompt_yes_no_question
 
 
 def add_parser(subparsers):
@@ -26,35 +27,33 @@ def add_parser(subparsers):
     )
     parser.add_argument(
         "--inputs", "-i", type=argparse.FileType("r"),
-        help="YAML or JSON file with inputs to "
-             "override the inputs supplied in init",
+        help="YAML or JSON file with inputs to override the inputs supplied in init",
     ).complete = shtab.FILE
     parser.add_argument(
-        "--workers", "-w",
-        help="Maximum number of concurrent deployment "
-             "threads (positive number, default 1)",
-        type=int, default=1
+        "--workers", "-w", type=int, default=1,
+        help="Maximum number of concurrent deployment threads (positive number, default 1)"
     )
+
     group = parser.add_mutually_exclusive_group()
     group.add_argument(
-        "--resume", "-r", action='store_true',
+        "--resume", "-r", action="store_true",
         help="Resume the deployment from where it was interrupted",
     )
     group.add_argument(
-        "--clean-state", "-c", action='store_true',
-        help="Clean the previous deployment state "
-             "and start over the deployment",
+        "--clean-state", "-c", action="store_true",
+        help="Clean the previous deployment state and start over the deployment",
     )
+
     parser.add_argument(
-        "--force", "-f", action='store_true',
+        "--force", "-f", action="store_true",
         help="Force the action and skip any possible prompts",
     )
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.add_argument(
-        "template", type=argparse.FileType("r"), nargs='?',
+        "template", type=argparse.FileType("r"), nargs="?",
         help="TOSCA YAML service template file",
     ).complete = shtab.FILE
     parser.set_defaults(func=_parser_callback)
@@ -62,8 +61,7 @@ def add_parser(subparsers):
 
 def _parser_callback(args):
     if args.instance_path and not path.isdir(args.instance_path):
-        raise argparse.ArgumentTypeError("Directory {} is not a valid path!"
-                                         .format(args.instance_path))
+        raise argparse.ArgumentTypeError("Directory {} is not a valid path!".format(args.instance_path))
 
     if args.workers < 1:
         print("{} is not a positive number!".format(args.workers))
@@ -76,8 +74,7 @@ def _parser_callback(args):
     if storage.exists("instances"):
         if args.resume and status == "interrupted":
             if not args.force:
-                print("The resume deploy option might have unexpected "
-                      "consequences on the already deployed blueprint.")
+                print("The resume deploy option might have unexpected consequences on the already deployed blueprint.")
                 question = prompt_yes_no_question()
                 if not question:
                     return 0
@@ -96,9 +93,8 @@ def _parser_callback(args):
             print("All instances have already been deployed.")
             return 0
         elif status == "interrupted":
-            print("The instance model already exists. Use --resume/-r to "
-                  "continue or --clean-state/-c to delete current deployment "
-                  "state and start over the deployment.")
+            print("The instance model already exists. Use --resume/-r to continue or --clean-state/-c to delete "
+                  "current deployment state and start over the deployment.")
             return 0
 
     if args.template:
@@ -107,8 +103,7 @@ def _parser_callback(args):
         if storage.exists("root_file"):
             service_template = storage.read("root_file")
         else:
-            print("CSAR or template root file does not exist. "
-                  "Maybe you have forgotten to initialize it.")
+            print("CSAR or template root file does not exist. Maybe you have forgotten to initialize it.")
             return 1
 
     try:
@@ -116,7 +111,7 @@ def _parser_callback(args):
             inputs = yaml.safe_load(args.inputs)
         else:
             inputs = None
-    except Exception as e:
+    except YAMLError as e:
         print("Invalid inputs: {}".format(e))
         return 1
 
@@ -139,14 +134,14 @@ def _parser_callback(args):
     return 0
 
 
-def deploy_service_template(service_template: str,
-                            inputs: typing.Optional[dict], storage: Storage,
-                            verbose_mode: bool, num_workers: int,
-                            delete_existing_state: bool):
-    """
-    :raises ParseError:
-    :raises DataError:
-    """
+def deploy_service_template(
+        service_template: str,
+        inputs: typing.Optional[dict],
+        storage: Storage,
+        verbose_mode: bool,
+        num_workers: int,
+        delete_existing_state: bool
+):
     if delete_existing_state:
         storage.remove("instances")
 
@@ -163,8 +158,7 @@ def deploy_service_template(service_template: str,
     if storage.exists("csars"):
         csar_dir = Path(storage.path) / "csars" / "csar"
         workdir = str(csar_dir)
-        ast = tosca.load(Path(csar_dir),
-                         PurePath(service_template).relative_to(csar_dir))
+        ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir))
     else:
         ast = tosca.load(Path.cwd(), PurePath(service_template))
 
@@ -174,13 +168,14 @@ def deploy_service_template(service_template: str,
     topology.deploy(verbose_mode, workdir, num_workers)
 
 
-def deploy_compressed_csar(csar_name: str, inputs: typing.Optional[dict],
-                           storage: Storage, verbose_mode: bool,
-                           num_workers: int, delete_existing_state: bool):
-    """
-    :raises ParseError:
-    :raises DataError:
-    """
+def deploy_compressed_csar(
+        csar_name: str,
+        inputs: typing.Optional[dict],
+        storage: Storage,
+        verbose_mode: bool,
+        num_workers: int,
+        delete_existing_state: bool
+):
     if delete_existing_state:
         storage.remove("instances")
 
@@ -197,7 +192,7 @@ def deploy_compressed_csar(csar_name: str, inputs: typing.Optional[dict],
 
     # unzip csar, save the path to storage and set workdir
     csar_dir = csars_dir / Path("csar")
-    ZipFile(csar_name, 'r').extractall(csar_dir)
+    ZipFile(csar_name, "r").extractall(csar_dir)
     csar_tosca_service_template_path = csar_dir / tosca_service_template
     storage.write(str(csar_tosca_service_template_path), "root_file")
     workdir = str(csar_dir)
diff --git a/src/opera/commands/diff.py b/src/opera/commands/diff.py
index c83077fe..08a593b2 100644
--- a/src/opera/commands/diff.py
+++ b/src/opera/commands/diff.py
@@ -1,24 +1,24 @@
 import argparse
-import typing
-import yaml
 import tempfile
-
-from pathlib import Path, PurePath
+import typing
 from os import path
+from pathlib import Path, PurePath
+
+import yaml
+from yaml import YAMLError
 
+from opera.compare.instance_comparer import InstanceComparer
+from opera.compare.template_comparer import TemplateComparer, TemplateContext
 from opera.error import DataError, ParseError
 from opera.parser import tosca
 from opera.storage import Storage
-from opera.compare.template_comparer import TemplateComparer, TemplateContext
-from opera.compare.instance_comparer import InstanceComparer
 from opera.utils import format_outputs, save_outputs, get_template, get_workdir
 
 
 def add_parser(subparsers):
     parser = subparsers.add_parser(
         "diff",
-        help="Compare TOSCA service template to the one from "
-             "the opera project storage and print out their differences"
+        help="Compare TOSCA service template to the one from the opera project storage and print out their differences"
     )
     parser.add_argument(
         "--instance-path", "-p",
@@ -26,15 +26,14 @@ def add_parser(subparsers):
     )
     parser.add_argument(
         "--inputs", "-i", type=argparse.FileType("r"),
-        help="Optional: YAML or JSON file with inputs "
-             "that will be used along with the comparison",
+        help="Optional: YAML or JSON file with inputs that will be used along with the comparison",
     )
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.add_argument(
-        "--template-only", "-t", action='store_true',
+        "--template-only", "-t", action="store_true",
         help="Compare only templates without instances",
     )
     parser.add_argument(
@@ -45,17 +44,16 @@ def add_parser(subparsers):
         "--output", "-o",
         help="Output file location"
     )
-    parser.add_argument("template",
-                        type=argparse.FileType("r"), nargs='?',
-                        help="TOSCA YAML service template file",
-                        )
+    parser.add_argument(
+        "template", type=argparse.FileType("r"), nargs="?",
+        help="TOSCA YAML service template file",
+    )
     parser.set_defaults(func=_parser_callback)
 
 
 def _parser_callback(args):
     if args.instance_path and not path.isdir(args.instance_path):
-        raise argparse.ArgumentTypeError("Directory {} is not a valid path!"
-                                         .format(args.instance_path))
+        raise argparse.ArgumentTypeError("Directory {} is not a valid path!".format(args.instance_path))
 
     storage_old = Storage.create(args.instance_path)
     comparer = TemplateComparer()
@@ -82,7 +80,7 @@ def _parser_callback(args):
             inputs_new = yaml.safe_load(args.inputs)
         else:
             inputs_new = {}
-    except Exception as e:
+    except YAMLError as e:
         print("Invalid inputs: {}".format(e))
         return 1
 
@@ -91,21 +89,29 @@ def _parser_callback(args):
 
     try:
         if args.template_only:
-            template_diff = diff_templates(service_template_old,
-                                           workdir_old, inputs_old,
-                                           service_template_new,
-                                           workdir_new, inputs_new,
-                                           comparer, args.verbose)
+            template_diff = diff_templates(
+                service_template_old,
+                workdir_old,
+                inputs_old,
+                service_template_new,
+                workdir_new,
+                inputs_new,
+                comparer,
+                args.verbose
+            )
         else:
             instance_comparer = InstanceComparer()
             with tempfile.TemporaryDirectory() as temp_path:
                 storage_new = Storage.create(temp_path)
                 storage_new.write_json(inputs_new, "inputs")
                 storage_new.write(service_template_new, "root_file")
-                template_diff = diff_instances(storage_old, workdir_old,
-                                               storage_new, workdir_new,
-                                               comparer,
-                                               instance_comparer, args.verbose)
+                template_diff = diff_instances(
+                    storage_old, workdir_old,
+                    storage_new, workdir_new,
+                    comparer,
+                    instance_comparer,
+                    args.verbose
+                )
         outputs = template_diff.outputs()
         if args.output:
             save_outputs(outputs, args.format, args.output)
@@ -121,15 +127,16 @@ def _parser_callback(args):
     return 0
 
 
-def diff_templates(service_template_old: str, workdir_old: str,
-                   inputs_old: typing.Optional[dict],
-                   service_template_new: str, workdir_new: str,
-                   inputs_new: typing.Optional[dict],
-                   template_comparer: TemplateComparer, verbose_mode: bool):
-    """
-    :raises ParseError:
-    :raises DataError:
-    """
+def diff_templates(
+        service_template_old: str,
+        workdir_old: str,
+        inputs_old: typing.Optional[dict],
+        service_template_new: str,
+        workdir_new: str,
+        inputs_new: typing.Optional[dict],
+        template_comparer: TemplateComparer,
+        verbose_mode: bool
+):
     if inputs_new is None:
         inputs_new = {}
 
@@ -141,43 +148,28 @@ def diff_templates(service_template_old: str, workdir_old: str,
 
     template_old = ast_old.get_template(inputs_old)
     template_new = ast_new.get_template(inputs_new)
-    context = TemplateContext(template_old,
-                              template_new,
-                              workdir_old,
-                              workdir_new)
-
-    equal, diff = template_comparer.compare_service_template(template_old,
-                                                             template_new,
-                                                             context)
-    return diff
+    context = TemplateContext(template_old, template_new, workdir_old, workdir_new)
 
+    _, diff = template_comparer.compare_service_template(template_old, template_new, context)
+    return diff
 
-def diff_instances(storage_old: Storage, workdir_old: str,
-                   storage_new: Storage, workdir_new: str,
-                   template_comparer: TemplateComparer,
-                   instance_comparer: InstanceComparer,
-                   verbose_mode: bool):
-    """
-    :raises ParseError:
-    :raises DataError:
-    """
 
+def diff_instances(
+        storage_old: Storage,
+        workdir_old: str,
+        storage_new: Storage,
+        workdir_new: str,
+        template_comparer: TemplateComparer,
+        instance_comparer: InstanceComparer,
+        verbose_mode: bool
+):
     template_old = get_template(storage_old)
     template_new = get_template(storage_new)
     topology_old = template_old.instantiate(storage_old)
     topology_new = template_new.instantiate(storage_new)
 
-    context = TemplateContext(template_old,
-                              template_new,
-                              workdir_old,
-                              workdir_new)
-
-    equal, diff = template_comparer.compare_service_template(template_old,
-                                                             template_new,
-                                                             context)
-
-    equal, diff = instance_comparer.compare_topology_template(topology_old,
-                                                              topology_new,
-                                                              diff)
+    context = TemplateContext(template_old, template_new, workdir_old, workdir_new)
+    _, diff = template_comparer.compare_service_template(template_old, template_new, context)
+    _, diff = instance_comparer.compare_topology_template(topology_old, topology_new, diff)
 
     return diff
diff --git a/src/opera/commands/info.py b/src/opera/commands/info.py
index 7892401f..046549c9 100644
--- a/src/opera/commands/info.py
+++ b/src/opera/commands/info.py
@@ -1,11 +1,12 @@
 import argparse
-import yaml
-import shtab
-
 from os import path
 from pathlib import Path, PurePath
+from typing import Dict
 from typing import Optional
 
+import shtab
+import yaml
+
 from opera.error import DataError, ParseError, OperaError
 from opera.parser import tosca
 from opera.parser.tosca.csar import CloudServiceArchive
@@ -23,25 +24,23 @@ def add_parser(subparsers):
         help=".opera storage folder location"
     ).complete = shtab.DIR
     parser.add_argument(
-        "--format", "-f", choices=("yaml", "json"), type=str,
-        default="yaml", help="Output format",
+        "--format", "-f", choices=("yaml", "json"), type=str, default="yaml",
+        help="Output format",
     )
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.add_argument(
-        "csar_or_rootdir", nargs='?',
-        help="Path to a packed or unpacked CSAR. "
-             "Defaults to the current directory if not specified.",
+        "csar_or_rootdir", nargs="?",
+        help="Path to a packed or unpacked CSAR. Defaults to the current directory if not specified.",
     ).complete = shtab.DIR
     parser.set_defaults(func=_parser_callback)
 
 
 def _parser_callback(args):
     if args.instance_path and not path.isdir(args.instance_path):
-        raise argparse.ArgumentTypeError("Directory {0} is not a valid path!"
-                                         .format(args.instance_path))
+        raise argparse.ArgumentTypeError("Directory {0} is not a valid path!".format(args.instance_path))
 
     storage = Storage.create(args.instance_path)
     try:
@@ -57,11 +56,7 @@ def _parser_callback(args):
 
 
 def info(csar_or_rootdir: Optional[PurePath], storage: Storage) -> dict:
-    """
-    :raises ParseError:
-    :raises DataError:
-    """
-    info_dict = dict(
+    info_dict: Dict[str, Optional[str]] = dict(
         service_template=None,
         content_root=None,
         inputs=None,
@@ -74,7 +69,7 @@ def info(csar_or_rootdir: Optional[PurePath], storage: Storage) -> dict:
         csar = CloudServiceArchive.create(csar_or_rootdir)
         try:
             csar.validate_csar()
-            info_dict["content_root"] = csar_or_rootdir
+            info_dict["content_root"] = str(csar_or_rootdir)
 
             meta = csar.parse_csar_meta()
             if meta is not None:
@@ -95,8 +90,7 @@ def info(csar_or_rootdir: Optional[PurePath], storage: Storage) -> dict:
         if storage.exists("csars/csar"):
             csar_dir = Path(storage.path) / "csars" / "csar"
             info_dict["content_root"] = str(csar_dir)
-            ast = tosca.load(Path(csar_dir),
-                             PurePath(service_template).relative_to(csar_dir))
+            ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir))
         else:
             ast = tosca.load(Path.cwd(), PurePath(service_template))
 
diff --git a/src/opera/commands/init.py b/src/opera/commands/init.py
index 9adad71d..2402a48d 100644
--- a/src/opera/commands/init.py
+++ b/src/opera/commands/init.py
@@ -1,13 +1,14 @@
 import argparse
 import typing
-import yaml
-import shtab
-
 from os import path
 from pathlib import Path, PurePath
 from zipfile import ZipFile, is_zipfile
 
-from opera.error import DataError, ParseError
+import shtab
+import yaml
+from yaml import YAMLError
+
+from opera.error import DataError, ParseError, OperaError
 from opera.parser import tosca
 from opera.parser.tosca.csar import CloudServiceArchive
 from opera.storage import Storage
@@ -16,8 +17,7 @@
 def add_parser(subparsers):
     parser = subparsers.add_parser(
         "init",
-        help="Initialize the deployment environment "
-             "for the service template or CSAR"
+        help="Initialize the deployment environment for the service template or CSAR"
     )
     parser.add_argument(
         "--instance-path", "-p",
@@ -28,12 +28,11 @@ def add_parser(subparsers):
         help="YAML or JSON file with inputs",
     ).complete = shtab.FILE
     parser.add_argument(
-        "--clean", "-c", action='store_true',
-        help="Clean storage by removing previously "
-             "initialized service template or CSAR",
+        "--clean", "-c", action="store_true",
+        help="Clean storage by removing previously initialized service template or CSAR",
     )
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.add_argument(
@@ -44,17 +43,15 @@ def add_parser(subparsers):
 
 
 def _parser_callback(args):
-    print("Warning: 'opera init' command is deprecated and will probably be "
-          "removed within one of the next releases. Please use 'opera deploy' "
-          "to initialize and deploy service templates or compressed CSARs.")
+    print("Warning: 'opera init' command is deprecated and will probably be removed within one of the next releases. "
+          "Please use 'opera deploy' to initialize and deploy service templates or compressed CSARs.")
     if args.instance_path and not path.isdir(args.instance_path):
-        raise argparse.ArgumentTypeError("Directory {} is not a valid path!"
-                                         .format(args.instance_path))
+        raise argparse.ArgumentTypeError("Directory {} is not a valid path!".format(args.instance_path))
 
     storage = Storage.create(args.instance_path)
     try:
         inputs = yaml.safe_load(args.inputs) if args.inputs else {}
-    except Exception as e:
+    except YAMLError as e:
         print("Invalid inputs: {}".format(e))
         return 1
 
@@ -71,22 +68,21 @@ def _parser_callback(args):
     except DataError as e:
         print(str(e))
         return 1
-    except Exception as e:
+    except OperaError as e:
         print("Invalid CSAR: {}".format(e))
         return 1
 
     return 0
 
 
-def init_compressed_csar(csar_name: str, inputs: typing.Optional[dict],
-                         storage: Storage, clean_storage: bool):
+def init_compressed_csar(csar_name: str, inputs: typing.Optional[dict], storage: Storage, clean_storage: bool):
     if storage.exists("root_file"):
         if clean_storage:
             storage.remove_all()
         else:
-            print("Looks like service template or CSAR has already been "
-                  "initialized. Use --clean/-c flag to clear the storage.")
-            return 1
+            print("Looks like service template or CSAR has already been initialized. "
+                  "Use the --clean/-c flag to clear the storage.")
+            return
 
     if inputs is None:
         inputs = {}
@@ -101,7 +97,7 @@ def init_compressed_csar(csar_name: str, inputs: typing.Optional[dict],
 
     # unzip csar and save the path to storage
     csar_dir = csars_dir / Path("csar")
-    ZipFile(csar_name, 'r').extractall(csar_dir)
+    ZipFile(csar_name, "r").extractall(csar_dir)
     csar_tosca_service_template_path = csar_dir / tosca_service_template
     storage.write(str(csar_tosca_service_template_path), "root_file")
 
@@ -117,9 +113,9 @@ def init_service_template(service_template: str, inputs: typing.Optional[dict],
         if clean_storage:
             storage.remove_all()
         else:
-            print("Looks like service template or CSAR has already been "
-                  "initialized. Use --clean/-c flag to clear the storage.")
-            return 1
+            print("Looks like service template or CSAR has already been initialized. "
+                  "Use --clean/-c flag to clear the storage.")
+            return
 
     if inputs is None:
         inputs = {}
diff --git a/src/opera/commands/outputs.py b/src/opera/commands/outputs.py
index 34ffaa05..7bd90c12 100644
--- a/src/opera/commands/outputs.py
+++ b/src/opera/commands/outputs.py
@@ -1,8 +1,9 @@
 import argparse
-import shtab
-
 from os import path
 from pathlib import Path, PurePath
+from typing import Dict
+
+import shtab
 
 from opera.error import DataError, ParseError
 from opera.parser import tosca
@@ -20,11 +21,11 @@ def add_parser(subparsers):
         help=".opera storage folder location"
     ).complete = shtab.DIR
     parser.add_argument(
-        "--format", "-f", choices=("yaml", "json"), type=str,
-        default="yaml", help="Output format",
+        "--format", "-f", choices=("yaml", "json"), type=str, default="yaml",
+        help="Output format",
     )
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.set_defaults(func=_parser_callback)
@@ -32,8 +33,7 @@ def add_parser(subparsers):
 
 def _parser_callback(args):
     if args.instance_path and not path.isdir(args.instance_path):
-        raise argparse.ArgumentTypeError("Directory {} is not a valid path!"
-                                         .format(args.instance_path))
+        raise argparse.ArgumentTypeError("Directory {} is not a valid path!".format(args.instance_path))
 
     storage = Storage.create(args.instance_path)
 
@@ -51,6 +51,8 @@ def _parser_callback(args):
 
 def outputs(storage: Storage) -> dict:
     """
+    Get deployment outputs.
+
     :raises ParseError:
     :raises DataError:
     """
@@ -64,8 +66,7 @@ def outputs(storage: Storage) -> dict:
 
         if storage.exists("csars"):
             csar_dir = Path(storage.path) / "csars" / "csar"
-            ast = tosca.load(Path(csar_dir),
-                             PurePath(service_template).relative_to(csar_dir))
+            ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir))
         else:
             ast = tosca.load(Path.cwd(), PurePath(service_template))
 
@@ -73,7 +74,8 @@ def outputs(storage: Storage) -> dict:
         # We need to instantiate the template in order
         # to get access to the instance state.
         template.instantiate(storage)
-        return template.get_outputs()
+        result: Dict = template.get_outputs()
+        return result
     else:
         print("There is no root_file in storage.")
         return {}
diff --git a/src/opera/commands/package.py b/src/opera/commands/package.py
index 4d8a8302..17c3a331 100644
--- a/src/opera/commands/package.py
+++ b/src/opera/commands/package.py
@@ -1,8 +1,8 @@
 import argparse
-import shtab
-
 from pathlib import Path, PurePath
 
+import shtab
+
 from opera.error import DataError, ParseError
 from opera.parser.tosca.csar import CloudServiceArchive
 from opera.utils import generate_random_pathname
@@ -15,40 +15,37 @@ def add_parser(subparsers):
     )
     parser.add_argument(
         "--service-template", "-t",
-        help="Name or path to the TOSCA service template "
-             "file from the root of the input folder",
+        help="Name or path to the TOSCA service template file from the root of the input folder",
     )
     parser.add_argument(
         "--output", "-o",
         help="Output CSAR file path",
     )
     parser.add_argument(
-        "--format", "-f", choices=("zip", "tar"),
-        default="zip", help="CSAR compressed file format",
+        "--format", "-f", choices=("zip", "tar"), default="zip",
+        help="CSAR compressed file format",
     )
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.add_argument(
         "service_template_folder",
-        help="Path to the root of the service template or "
-             "folder you want to create the TOSCA CSAR from"
+        help="Path to the root of the service template or folder you want to create the TOSCA CSAR from"
     ).complete = shtab.FILE
     parser.set_defaults(func=_parser_callback)
 
 
 def _parser_callback(args):
     if not Path(args.service_template_folder).is_dir():
-        raise argparse.ArgumentTypeError("Directory {} is not a valid path!"
-                                         .format(args.service_template_folder))
+        raise argparse.ArgumentTypeError("Directory {} is not a valid path!".format(args.service_template_folder))
 
     # if the output is set use it, if not create a random file name with UUID
     if args.output:
         # remove file extension if needed (".zip" or ".tar")
         # because shutil.make_archive already adds the extension
         if args.output.endswith("." + args.format):
-            csar_output = str(Path(args.output).with_suffix(''))
+            csar_output = str(Path(args.output).with_suffix(""))
         else:
             csar_output = str(Path(args.output))
 
@@ -57,8 +54,7 @@ def _parser_callback(args):
         csar_output = generate_random_pathname("opera-package-")
 
     try:
-        output_package = package(args.service_template_folder, csar_output,
-                                 args.service_template, args.format)
+        output_package = package(args.service_template_folder, csar_output, args.service_template, args.format)
         print("CSAR was created and packed to '{}'.".format(output_package))
     except ParseError as e:
         print("{}: {}".format(e.loc, e))
@@ -70,11 +66,7 @@ def _parser_callback(args):
     return 0
 
 
-def package(input_dir: str, csar_output: str, service_template: str,
-            csar_format: str) -> str:
-    """
-    :raises ParseError:
-    :raises DataError:
-    """
+def package(input_dir: str, csar_output: str, service_template: str, csar_format: str) -> str:
     csar = CloudServiceArchive.create(PurePath(input_dir))
-    return csar.package_csar(csar_output, service_template, csar_format)
+    result: str = csar.package_csar(csar_output, service_template, csar_format)
+    return result
diff --git a/src/opera/commands/undeploy.py b/src/opera/commands/undeploy.py
index b4023e94..304935f2 100644
--- a/src/opera/commands/undeploy.py
+++ b/src/opera/commands/undeploy.py
@@ -1,14 +1,14 @@
 import argparse
-import shtab
-
-from pathlib import Path, PurePath
 from os import path
+from pathlib import Path, PurePath
+
+import shtab
 
 from opera.commands.info import info
-from opera.utils import prompt_yes_no_question
 from opera.error import DataError, ParseError
 from opera.parser import tosca
 from opera.storage import Storage
+from opera.utils import prompt_yes_no_question
 
 
 def add_parser(subparsers):
@@ -21,21 +21,19 @@ def add_parser(subparsers):
         help=".opera storage folder location"
     ).complete = shtab.DIR
     parser.add_argument(
-        "--workers", "-w",
-        help="Maximum number of concurrent undeployment "
-             "threads (positive number, default 1)",
-        type=int, default=1
+        "--workers", "-w", type=int, default=1,
+        help="Maximum number of concurrent undeployment threads (positive number, default 1)"
     )
     parser.add_argument(
-        "--resume", "-r", action='store_true',
+        "--resume", "-r", action="store_true",
         help="Resume the undeployment from where it was interrupted",
     )
     parser.add_argument(
-        "--force", "-f", action='store_true',
+        "--force", "-f", action="store_true",
         help="Force the action and skip any possible prompts",
     )
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.set_defaults(func=_parser_callback)
@@ -43,8 +41,7 @@ def add_parser(subparsers):
 
 def _parser_callback(args):
     if args.instance_path and not path.isdir(args.instance_path):
-        raise argparse.ArgumentTypeError("Directory {} is not a valid path!"
-                                         .format(args.instance_path))
+        raise argparse.ArgumentTypeError("Directory {} is not a valid path!".format(args.instance_path))
 
     if args.workers < 1:
         print("{} is not a positive number!".format(args.workers))
@@ -56,14 +53,13 @@ def _parser_callback(args):
     if storage.exists("instances"):
         if args.resume and status == "interrupted":
             if not args.force:
-                print("The resume undeploy option might have unexpected "
-                      "consequences on the already undeployed blueprint.")
+                print("The resume undeploy option might have unexpected consequences on the already "
+                      "undeployed blueprint.")
                 question = prompt_yes_no_question()
                 if not question:
                     return 0
         elif status == "interrupted":
-            print("The instance model already exists. Use --resume/-r option "
-                  "to continue current undeployment process.")
+            print("The instance model already exists. Use --resume/-r option to continue current undeployment process.")
             return 0
         elif status == "undeployed":
             print("All instances have already been undeployed.")
@@ -83,6 +79,8 @@ def _parser_callback(args):
 
 def undeploy(storage: Storage, verbose_mode: bool, num_workers: int):
     """
+    Undeploy a deployment.
+
     :raises ParseError:
     :raises DataError:
     """
@@ -98,8 +96,7 @@ def undeploy(storage: Storage, verbose_mode: bool, num_workers: int):
         if storage.exists("csars"):
             csar_dir = Path(storage.path) / "csars" / "csar"
             workdir = str(csar_dir)
-            ast = tosca.load(Path(csar_dir),
-                             PurePath(service_template).relative_to(csar_dir))
+            ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir))
         else:
             ast = tosca.load(Path.cwd(), PurePath(service_template))
 
@@ -108,4 +105,3 @@ def undeploy(storage: Storage, verbose_mode: bool, num_workers: int):
         topology.undeploy(verbose_mode, workdir, num_workers)
     else:
         print("There is no root_file in storage.")
-        return 0
diff --git a/src/opera/commands/unpackage.py b/src/opera/commands/unpackage.py
index ea09e09b..1bca5dc2 100644
--- a/src/opera/commands/unpackage.py
+++ b/src/opera/commands/unpackage.py
@@ -1,8 +1,8 @@
 import argparse
-import shtab
-
 from pathlib import Path, PurePath
 
+import shtab
+
 from opera.error import DataError, ParseError
 from opera.parser.tosca.csar import CloudServiceArchive
 from opera.utils import determine_archive_format, generate_random_pathname
@@ -15,16 +15,16 @@ def add_parser(subparsers):
     )
     parser.add_argument(
         "--destination", "-d",
-        help="Path to the location where the CSAR file will be extracted to, "
-             "the path will be generated in the current working directory if "
-             "it isn't specified",
+        help="Path to the location where the CSAR file will be extracted to, the path will be generated in the "
+             "current working directory if it isn't specified",
     ).complete = shtab.DIR
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.add_argument(
-        "csar", help="Path to the compressed TOSCA CSAR"
+        "csar",
+        help="Path to the compressed TOSCA CSAR"
     ).complete = shtab.FILE
     parser.set_defaults(func=_parser_callback)
 
@@ -32,8 +32,7 @@ def add_parser(subparsers):
 def _parser_callback(args):
     csar_path = Path(args.csar)
     if not csar_path.is_file():
-        raise argparse.ArgumentTypeError("CSAR file {} is not a valid path!"
-                                         .format(args.csar))
+        raise argparse.ArgumentTypeError("CSAR file {} is not a valid path!".format(args.csar))
 
     # if the output is set use it, if not create a random file name with UUID
     if args.destination:
@@ -60,10 +59,6 @@ def _parser_callback(args):
 
 
 def unpackage(csar_input: str, output_dir: str, csar_format: str):
-    """
-    :raises ParseError:
-    :raises DataError:
-    """
     csar = CloudServiceArchive.create(PurePath(csar_input))
     # validate CSAR before unpacking it
     csar.validate_csar()
diff --git a/src/opera/commands/update.py b/src/opera/commands/update.py
index 0560d3fe..a7befbc2 100644
--- a/src/opera/commands/update.py
+++ b/src/opera/commands/update.py
@@ -1,23 +1,23 @@
 import argparse
-import yaml
 import tempfile
-
 from os import path
 
+import yaml
+from yaml import YAMLError
+
+from opera.commands.diff import diff_instances
+from opera.compare.diff import Diff
+from opera.compare.instance_comparer import InstanceComparer
+from opera.compare.template_comparer import TemplateComparer
 from opera.error import DataError, ParseError
 from opera.storage import Storage
-from opera.compare.template_comparer import TemplateComparer
-from opera.compare.instance_comparer import InstanceComparer
-from opera.compare.diff import Diff
 from opera.utils import format_outputs, get_template, get_workdir
-from opera.commands.diff import diff_instances
 
 
 def add_parser(subparsers):
     parser = subparsers.add_parser(
         "update",
-        help="Update the deployed TOSCA service template and redeploy "
-             "it according to the discovered template diff"
+        help="Update the deployed TOSCA service template and redeploy it according to the discovered template diff"
     )
     parser.add_argument(
         "--instance-path", "-p",
@@ -25,30 +25,26 @@ def add_parser(subparsers):
     )
     parser.add_argument(
         "--inputs", "-i", type=argparse.FileType("r"),
-        help="Optional: YAML or JSON file with inputs "
-             "that will be used for deployment update",
+        help="Optional: YAML or JSON file with inputs that will be used for deployment update",
     )
     parser.add_argument(
-        "--workers", "-w",
-        help="Maximum number of concurrent update "
-             "threads (positive number, default 1)",
-        type=int, default=1
+        "--workers", "-w", type=int, default=1,
+        help="Maximum number of concurrent update threads (positive number, default 1)"
     )
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
-    parser.add_argument("template",
-                        type=argparse.FileType("r"), nargs='?',
-                        help="TOSCA YAML service template file",
-                        )
+    parser.add_argument(
+        "template", type=argparse.FileType("r"), nargs="?",
+        help="TOSCA YAML service template file",
+    )
     parser.set_defaults(func=_parser_callback)
 
 
 def _parser_callback(args):
     if args.instance_path and not path.isdir(args.instance_path):
-        raise argparse.ArgumentTypeError("Directory {} is not a valid path!"
-                                         .format(args.instance_path))
+        raise argparse.ArgumentTypeError("Directory {} is not a valid path!".format(args.instance_path))
 
     if args.workers < 1:
         print("{} is not a positive number!".format(args.workers))
@@ -69,7 +65,7 @@ def _parser_callback(args):
             inputs_new = yaml.safe_load(args.inputs)
         else:
             inputs_new = {}
-    except Exception as e:
+    except YAMLError as e:
         print("Invalid inputs: {}".format(e))
         return 1
 
@@ -82,15 +78,23 @@ def _parser_callback(args):
             storage_new.write(service_template_new, "root_file")
             workdir_new = get_workdir(storage_new)
 
-            instance_diff = diff_instances(storage_old, workdir_old,
-                                           storage_new, workdir_new,
-                                           comparer,
-                                           instance_comparer, args.verbose)
-
-            update(storage_old, workdir_old,
-                   storage_new, workdir_new,
-                   instance_comparer, instance_diff,
-                   args.verbose, args.workers, overwrite=True)
+            instance_diff = diff_instances(
+                storage_old, workdir_old,
+                storage_new, workdir_new,
+                comparer,
+                instance_comparer,
+                args.verbose
+            )
+
+            update(
+                storage_old, workdir_old,
+                storage_new, workdir_new,
+                instance_comparer,
+                instance_diff,
+                args.verbose,
+                args.workers,
+                overwrite=True
+            )
 
     except ParseError as e:
         print("{}: {}".format(e.loc, e))
@@ -102,14 +106,15 @@ def _parser_callback(args):
     return 0
 
 
-def update(storage_old: Storage, workdir_old: str,
-           storage_new: Storage, workdir_new: str,
-           instance_comparer: InstanceComparer, instance_diff: Diff,
-           verbose_mode: bool, num_workers: int, overwrite: bool):
-    """
-    :raises ParseError:
-    :raises DataError:
-    """
+def update(
+        storage_old: Storage, workdir_old: str,
+        storage_new: Storage, workdir_new: str,
+        instance_comparer: InstanceComparer,
+        instance_diff: Diff,
+        verbose_mode: bool,
+        num_workers: int,
+        overwrite: bool
+):
 
     template_old = get_template(storage_old)
     template_new = get_template(storage_new)
@@ -118,6 +123,7 @@ def update(storage_old: Storage, workdir_old: str,
 
     if verbose_mode:
         print(format_outputs(instance_diff.outputs(), "json"))
+
     instance_comparer.prepare_update(topology_old, topology_new, instance_diff)
     topology_old.undeploy(verbose_mode, workdir_old, num_workers)
     topology_old.write_all()
diff --git a/src/opera/commands/validate.py b/src/opera/commands/validate.py
index d388e153..ea657325 100644
--- a/src/opera/commands/validate.py
+++ b/src/opera/commands/validate.py
@@ -1,12 +1,13 @@
 import argparse
 import typing
-import yaml
-import shtab
-
-from tempfile import TemporaryDirectory
 from pathlib import Path, PurePath
+from tempfile import TemporaryDirectory
 from zipfile import ZipFile, is_zipfile
 
+import shtab
+import yaml
+from yaml import YAMLError
+
 from opera.error import DataError, ParseError
 from opera.parser import tosca
 from opera.parser.tosca.csar import CloudServiceArchive
@@ -22,7 +23,7 @@ def add_parser(subparsers):
         help="YAML or JSON file with inputs",
     ).complete = shtab.FILE
     parser.add_argument(
-        "--verbose", "-v", action='store_true',
+        "--verbose", "-v", action="store_true",
         help="Turns on verbose mode",
     )
     parser.add_argument(
@@ -35,7 +36,7 @@ def add_parser(subparsers):
 def _parser_callback(args):
     try:
         inputs = yaml.safe_load(args.inputs) if args.inputs else {}
-    except Exception as e:
+    except YAMLError as e:
         print("Invalid inputs: {}".format(e))
         return 1
 
@@ -67,15 +68,14 @@ def validate_compressed_csar(csar_name: str, inputs: typing.Optional[dict]):
         tosca_service_template = csar.get_entrypoint()
 
         # unzip csar to temporary folder
-        ZipFile(csar_name, 'r').extractall(csar_validation_dir)
+        ZipFile(csar_name, "r").extractall(csar_validation_dir)
 
         # try to initiate service template from csar
         ast = tosca.load(Path(csar_validation_dir), Path(tosca_service_template))
         ast.get_template(inputs)
 
 
-def validate_service_template(service_template: str,
-                              inputs: typing.Optional[dict]):
+def validate_service_template(service_template: str, inputs: typing.Optional[dict]):
     if inputs is None:
         inputs = {}
     ast = tosca.load(Path.cwd(), PurePath(service_template))
diff --git a/src/opera/compare/comparisons.py b/src/opera/compare/comparisons.py
index 001ba44a..2cb9bd24 100644
--- a/src/opera/compare/comparisons.py
+++ b/src/opera/compare/comparisons.py
@@ -14,11 +14,10 @@ def __init__(self, compare_func, id_func):
         super().__init__(compare_func)
         self.item_id_func = id_func
 
-    def compare(self, list1, list2, context):
+    def compare(self, list1, list2, context):  # pylint: disable=arguments-differ
         diff = Diff()
         for item1 in list1:
-            item2 = next((i for i in list2 if (self.item_id_func(item1) ==
-                                               self.item_id_func(i))), None)
+            item2 = next((i for i in list2 if self.item_id_func(item1) == self.item_id_func(i)), None)
             if not item2:
                 diff.deleted.append(self.item_id_func(item1))
             else:
@@ -26,8 +25,7 @@ def compare(self, list1, list2, context):
                 if not equal:
                     diff.changed[self.item_id_func(item1)] = change
         for item2 in list2:
-            item1 = next((i for i in list1 if (self.item_id_func(item2) ==
-                                               self.item_id_func(i))), None)
+            item1 = next((i for i in list1 if self.item_id_func(item2) == self.item_id_func(i)), None)
             if not item1:
                 diff.added.append(self.item_id_func(item2))
 
@@ -39,11 +37,12 @@ def __init__(self, compare_func, id_func=None):
         super().__init__(compare_func)
         self.item_id_func = id_func
 
-    def compare(self, dict1, dict2, context):
+    def compare(self, dict1, dict2, context):  # pylint: disable=arguments-differ
         if dict1 is None:
             dict1 = {}
         if dict2 is None:
             dict2 = {}
+
         # special handling for capability properties and attributes
         if isinstance(dict1, tuple):
             dict1 = dict1[0]
@@ -55,9 +54,7 @@ def compare(self, dict1, dict2, context):
             if name1 not in dict2:
                 diff.deleted.append(name1)
             else:
-                equal, change = self.item_compare_func(item1,
-                                                       dict2[name1],
-                                                       context)
+                equal, change = self.item_compare_func(item1, dict2[name1], context)
                 if not equal:
                     if self.item_id_func is None:
                         name = name1
@@ -65,7 +62,7 @@ def compare(self, dict1, dict2, context):
                         name = self.item_id_func(item1)
                     diff.changed[name] = change
 
-        for name2, item2 in dict2.items():
+        for name2 in dict2:
             if name2 not in dict1:
                 diff.added.append(name2)
 
diff --git a/src/opera/compare/diff.py b/src/opera/compare/diff.py
index f2d8b96a..d4c712e6 100644
--- a/src/opera/compare/diff.py
+++ b/src/opera/compare/diff.py
@@ -1,4 +1,5 @@
 import copy
+from typing import Dict, Union
 
 
 class Diff:
@@ -8,9 +9,7 @@ def __init__(self):
         self.deleted = []
 
     def equal(self):
-        return (len(self.added) == 0 and
-                len(self.changed) == 0 and
-                len(self.deleted) == 0)
+        return len(self.added) == 0 and len(self.changed) == 0 and len(self.deleted) == 0
 
     def outputs(self):
         return self.convert(self)
@@ -20,7 +19,7 @@ def convert(self, diff):
             return list(diff)
         if not isinstance(diff, Diff):
             return diff
-        contents = {}
+        contents: Dict[str, Union[list, dict]] = {}
         if len(diff.added) != 0:
             contents["added"] = diff.added
         if len(diff.deleted) != 0:
diff --git a/src/opera/compare/instance_comparer.py b/src/opera/compare/instance_comparer.py
index c5703f21..492f5d64 100644
--- a/src/opera/compare/instance_comparer.py
+++ b/src/opera/compare/instance_comparer.py
@@ -1,31 +1,27 @@
-from .diff import Diff
+from typing import Dict
+
 from .comparisons import MapComparison
+from .diff import Diff
 
 
 class InstanceComparer:
-    def compare_topology_template(self, topology_template1, topology_template2,
-                                  template_diff):
+    def compare_topology_template(self, topology_template1, topology_template2, template_diff):
         diff_copy = template_diff.copy()
         nodes_diff = diff_copy.changed.get("nodes", Diff())
         # we can just process model from second topology
         # as we only care about the relationships that are present
         root_nodes2 = self._get_root_nodes(topology_template2.nodes)
-        equal, diff = self._check_dependencies(root_nodes2.values(),
-                                               nodes_diff.changed, None, False)
+        equal, diff = self._check_dependencies(root_nodes2.values(), nodes_diff.changed, None, False)
         if not equal:
             nodes_diff.combine_changes("dependencies", diff)
-        compare_states = MapComparison(self._compare_state,
-                                       self._get_template_name)
-        equal, diff = compare_states.compare(topology_template1.nodes,
-                                             topology_template2.nodes,
-                                             None)
+        compare_states = MapComparison(self._compare_state, self._get_template_name)
+        equal, diff = compare_states.compare(topology_template1.nodes, topology_template2.nodes, None)
         if not equal:
             nodes_diff.combine_changes("state", diff.changed)
 
         return equal, diff_copy
 
-    def prepare_update(self, topology_template1, topology_template2,
-                       template_diff):
+    def prepare_update(self, topology_template1, topology_template2, template_diff):
         # no need to take relationships into account
         # as they are always in "initial" state
         nodes_diff = template_diff.changed.get("nodes", Diff())
@@ -39,19 +35,19 @@ def prepare_update(self, topology_template1, topology_template2,
             if not nodes_diff.find_key(node_name):
                 node2.set_state("started", write=False)
 
-    def _check_dependencies(self, nodes, changed_nodes,
-                            parent_name, parent_changed):
-        dependency_changes = {}
+    def _check_dependencies(self, nodes, changed_nodes, parent_name, parent_changed):
+        dependency_changes: Dict[str, set] = {}
         # dependency graph is acyclic so we may not care about
         # marking processed nodes
         for node in nodes:
             node_changed = node.template.name in changed_nodes
             for edge in node.in_edges.values():
-                equal, child_changes = self._check_dependencies(
+                _, child_changes = self._check_dependencies(
                     map(self._get_source, edge.values()),
                     changed_nodes,
                     node.template.name,
-                    node_changed)
+                    node_changed
+                )
                 for child_name, changes in child_changes.items():
                     node_dep = dependency_changes.get(child_name, set())
                     node_dep.update(changes)
@@ -65,20 +61,24 @@ def _check_dependencies(self, nodes, changed_nodes,
                     dependency_changes[node_name] = node_dep
         return len(dependency_changes) == 0, dependency_changes
 
-    def _get_root_nodes(self, nodes):
+    @staticmethod
+    def _get_root_nodes(nodes):
         root_nodes = {}
         for node_name, node in nodes.items():
             if len(node.out_edges) == 0:
                 root_nodes[node_name] = node
         return root_nodes
 
-    def _get_template_name(self, node):
+    @staticmethod
+    def _get_template_name(node):
         return node.template.name
 
-    def _get_source(self, relationship):
+    @staticmethod
+    def _get_source(relationship):
         return relationship.source
 
-    def _compare_state(self, node1, node2, context):
+    @staticmethod
+    def _compare_state(node1, node2, context):
         # comparing states we assume that all nodes in new instance model
         # would be in "started" state after deployment
         state1 = node1.attributes["state"].data
diff --git a/src/opera/compare/template_comparer.py b/src/opera/compare/template_comparer.py
index 48467194..c64798c4 100644
--- a/src/opera/compare/template_comparer.py
+++ b/src/opera/compare/template_comparer.py
@@ -1,13 +1,12 @@
 import filecmp
-
 from os import path
-from .diff import Diff
 
-from .comparisons import Comparison, ListComparison, MapComparison
 from opera.error import DataError
+from .comparisons import Comparison, ListComparison, MapComparison
+from .diff import Diff
 
 
-class TemplateContext:
+class TemplateContext:  # noqa: R0903
     def __init__(self, template1, template2, workdir1, workdir2):
         self.template1 = template1
         self.template2 = template2
@@ -16,27 +15,22 @@ def __init__(self, template1, template2, workdir1, workdir2):
 
 
 class TemplateComparer:
-    def compare_service_template(self, service_template1, service_template2,
-                                 context):
+    def compare_service_template(self, service_template1, service_template2, context):
         comparisons = {
             "nodes": MapComparison(self._compare_node),
         }
-        return self._compare_item(service_template1, service_template2,
-                                  comparisons, context)
+        return self._compare_item(service_template1, service_template2, comparisons, context)
 
     def _compare_node(self, node1, node2, context):
         comparisons = {
             "types": Comparison(self._compare_types),
             "properties": MapComparison(self._compare_value),
             "attributes": MapComparison(self._compare_none),
-            "requirements": ListComparison(self._compare_requirement,
-                                           self._get_name),
-            "capabilities": ListComparison(self._compare_capability,
-                                           self._get_name),
+            "requirements": ListComparison(self._compare_requirement, self._get_name),
+            "capabilities": ListComparison(self._compare_capability, self._get_name),
             "interfaces": MapComparison(self._compare_interface),
         }
-        new_context = TemplateContext(node1, node2,
-                                      context.workdir1, context.workdir2)
+        new_context = TemplateContext(node1, node2, context.workdir1, context.workdir2)
         return self._compare_item(node1, node2, comparisons, new_context)
 
     def _compare_requirement(self, req1, req2, context):
@@ -51,8 +45,7 @@ def _compare_capability(self, capability1, capability2, context):
             "properties": MapComparison(self._compare_capability_property),
             "attributes": MapComparison(self._compare_none)
         }
-        return self._compare_item(capability1, capability2, comparisons,
-                                  context)
+        return self._compare_item(capability1, capability2, comparisons, context)
 
     def _compare_relationship(self, rel1, rel2, context):
         comparisons = {
@@ -61,11 +54,8 @@ def _compare_relationship(self, rel1, rel2, context):
             "attributes": MapComparison(self._compare_none),
             "interfaces": MapComparison(self._compare_interface)
         }
-        new_context = TemplateContext(rel1, rel2,
-                                      context.workdir1, context.workdir2)
-        return self._compare_item(rel1, rel2,
-                                  comparisons,
-                                  new_context)
+        new_context = TemplateContext(rel1, rel2, context.workdir1, context.workdir2)
+        return self._compare_item(rel1, rel2, comparisons, new_context)
 
     def _compare_interface(self, interface1, interface2, context):
         comparisons = {
@@ -77,26 +67,24 @@ def _compare_operation(self, operation1, operation2, context):
         comparisons = {
             "primary": Comparison(self._compare_file),
             "inputs": MapComparison(self._compare_value),
-            "dependencies": ListComparison(self._compare_file,
-                                           self._get_filename),
-            "artifacts": ListComparison(self._compare_file,
-                                        self._get_filename)
+            "dependencies": ListComparison(self._compare_file, self._get_filename),
+            "artifacts": ListComparison(self._compare_file, self._get_filename)
         }
         return self._compare_item(operation1, operation2, comparisons, context)
 
-    def _compare_item(self, item1, item2, comparisons, context):
+    @staticmethod
+    def _compare_item(item1, item2, comparisons, context):
         diff = Diff()
         for name, comparison in comparisons.items():
             equal = True
             if isinstance(comparison, Comparison):
-                equal, change = comparison.compare(getattr(item1, name),
-                                                   getattr(item2, name),
-                                                   context)
+                equal, change = comparison.compare(getattr(item1, name), getattr(item2, name), context)
             if not equal:
                 diff.changed[name] = change
         return diff.equal(), diff
 
-    def _compare_value(self, val1, val2, context):
+    @staticmethod
+    def _compare_value(val1, val2, context):
         try:
             eval1 = val1.eval(context.template1, "")
         except DataError:
@@ -107,29 +95,38 @@ def _compare_value(self, val1, val2, context):
             eval2 = None
         return eval1 == eval2, [eval1, eval2]
 
-    def _compare_types(self, types1, types2, context):
+    @staticmethod
+    def _compare_types(types1, types2, context):
         type1 = types1[0]
         type2 = types2[0]
         return type1 == type2, [type1, type2]
 
-    def _compare_capability_property(self, prop1, prop2, context):
+    @staticmethod
+    def _compare_capability_property(prop1, prop2, context):
         return prop1.data == prop2.data, [prop1.data, prop2.data]
 
-    def _compare_none(self, attr1, attr2, context):
+    @staticmethod
+    def _compare_none(attr1, attr2, context):
         # do not compare attribute values
         return True, ""
 
-    def _compare_target(self, target1, target2, context):
+    @staticmethod
+    def _compare_target(target1, target2, context):
         return target1.name == target2.name, [target1.name, target2.name]
 
-    def _compare_file(self, filepath1, filepath2, context):
-        equal = filecmp.cmp(path.join(context.workdir1, filepath1),
-                            path.join(context.workdir2, filepath2),
-                            shallow=False)
+    @staticmethod
+    def _compare_file(filepath1, filepath2, context):
+        equal = filecmp.cmp(
+            path.join(context.workdir1, filepath1),
+            path.join(context.workdir2, filepath2),
+            shallow=False
+        )
         return equal, "file {0}".format(filepath1)
 
-    def _get_filename(self, filepath):
+    @staticmethod
+    def _get_filename(filepath):
         return str(filepath)
 
-    def _get_name(self, item):
+    @staticmethod
+    def _get_name(item):
         return item.name
diff --git a/src/opera/error.py b/src/opera/error.py
index 7b562ba9..63325668 100644
--- a/src/opera/error.py
+++ b/src/opera/error.py
@@ -1,9 +1,9 @@
 class OperaError(Exception):
-    """ Base opera exception for catch-all-opera-errors constructs. """
+    """Base opera exception for catch-all-opera-errors constructs."""
 
 
 class ParseError(OperaError):
-    """ Exception that is raised on invalid TOSCA document. """
+    """Exception that is raised on invalid TOSCA document."""
 
     def __init__(self, msg, loc):
         super().__init__(msg)
@@ -11,8 +11,8 @@ def __init__(self, msg, loc):
 
 
 class DataError(OperaError):
-    """ Exception that is raised on data errors that occur at runtime. """
+    """Exception that is raised on data errors that occur at runtime."""
 
 
 class OperationError(OperaError):
-    """ Raised on failed operation executions. """
+    """Raised on failed operation executions."""
diff --git a/src/opera/executor/ansible.py b/src/opera/executor/ansible.py
index c61a244f..62f09818 100644
--- a/src/opera/executor/ansible.py
+++ b/src/opera/executor/ansible.py
@@ -5,8 +5,8 @@
 
 import yaml
 
-from . import utils
 from opera.threading import utils as thread_utils
+from . import utils
 
 
 def _get_inventory(host):
@@ -27,22 +27,19 @@ def _get_inventory(host):
     return yaml.safe_dump(dict(all=dict(hosts=dict(opera=inventory))))
 
 
-def run(host, primary, dependencies, artifacts, vars, verbose, workdir):
+def run(host, primary, dependencies, artifacts, variables, verbose, workdir):  # pylint: disable=too-many-locals
     with tempfile.TemporaryDirectory() as dir_path:
         playbook = os.path.join(dir_path, os.path.basename(primary))
         utils.copy(os.path.join(workdir, primary), playbook)
+
         for d in dependencies:
-            utils.copy(os.path.join(workdir, d),
-                       os.path.join(dir_path, os.path.basename(d)))
+            utils.copy(os.path.join(workdir, d), os.path.join(dir_path, os.path.basename(d)))
         for a in artifacts:
-            utils.copy(os.path.join(workdir, a),
-                       os.path.join(dir_path, os.path.basename(a)))
-        inventory = utils.write(
-            dir_path, _get_inventory(host), suffix=".yaml",
-        )
-        vars_file = utils.write(
-            dir_path, yaml.safe_dump(vars), suffix=".yaml",
-        )
+            utils.copy(os.path.join(workdir, a), os.path.join(dir_path, os.path.basename(a)))
+
+        inventory = utils.write(dir_path, _get_inventory(host), suffix=".yaml")
+        vars_file = utils.write(dir_path, yaml.safe_dump(variables), suffix=".yaml")
+
         with open("{}/ansible.cfg".format(dir_path), "w") as fd:
             fd.write("[defaults]\n")
             fd.write("retry_files_enabled = False\n")
@@ -51,12 +48,12 @@ def run(host, primary, dependencies, artifacts, vars, verbose, workdir):
                 "OPERA_SSH_HOST_KEY_CHECKING")
             if opera_ssh_host_key_checking is not None:
                 check = str(opera_ssh_host_key_checking).lower().strip()
-                if check[:1] == 'f' or check[:1] == "false":
+                if check[:1] == "f" or check[:1] == "false":
                     fd.write("host_key_checking = False\n")
 
         if verbose:
             print("***inputs***")
-            print(["{}: {}".format(key, vars[key]) for key in vars])
+            print(["{}: {}".format(key, variables[key]) for key in variables])
             print("***inputs***")
 
         cmd = [
@@ -73,12 +70,12 @@ def run(host, primary, dependencies, artifacts, vars, verbose, workdir):
         if code != 0 or verbose:
             thread_utils.print_thread("------------")
             with open(out) as fd:
-                for l in fd:
-                    print(l.rstrip())
+                for line in fd:
+                    print(line.rstrip())
             thread_utils.print_thread("------------")
             with open(err) as fd:
-                for l in fd:
-                    print(l.rstrip())
+                for line in fd:
+                    print(line.rstrip())
             thread_utils.print_thread("============")
 
         if code != 0:
diff --git a/src/opera/executor/utils.py b/src/opera/executor/utils.py
index f1d68979..73d2a833 100644
--- a/src/opera/executor/utils.py
+++ b/src/opera/executor/utils.py
@@ -1,8 +1,8 @@
-import os
 import errno
+import os
 import shutil
+import subprocess  # nosec
 import tempfile
-import subprocess
 
 
 def copy(source, target):
@@ -16,25 +16,17 @@ def copy(source, target):
 
 
 def write(dest_dir, content, suffix=None):
-    dest = tempfile.NamedTemporaryFile(
-        dir=dest_dir, delete=False, suffix=suffix,
-    )
+    dest = tempfile.NamedTemporaryFile(dir=dest_dir, delete=False, suffix=suffix)
     dest.write(content.encode("utf-8"))
     dest.close()
     return dest.name
 
 
 def run_in_directory(dest_dir, cmd, env):
-    fstdout = tempfile.NamedTemporaryFile(
-        dir=dest_dir, delete=False, suffix=".stdout",
-    )
-    fstderr = tempfile.NamedTemporaryFile(
-        dir=dest_dir, delete=False, suffix=".stderr",
-    )
-    result = subprocess.run(
-        cmd, cwd=dest_dir, stdout=fstdout, stderr=fstderr,
-        env=dict(os.environ, **env),
-    )
+    fstdout = tempfile.NamedTemporaryFile(dir=dest_dir, delete=False, suffix=".stdout")
+    fstderr = tempfile.NamedTemporaryFile(dir=dest_dir, delete=False, suffix=".stderr")
+    result = subprocess.run(cmd, cwd=dest_dir, stdout=fstdout, stderr=fstderr,  # nosec
+                            env=dict(os.environ, **env), check=False)
     fstdout.close()
     fstderr.close()
     return result.returncode, fstdout.name, fstderr.name
diff --git a/src/opera/instance/base.py b/src/opera/instance/base.py
index 5335ee49..328975bf 100644
--- a/src/opera/instance/base.py
+++ b/src/opera/instance/base.py
@@ -1,13 +1,16 @@
 import itertools
 
 from opera.error import DataError, OperationError
+from opera.instance.topology import Topology
 from opera.value import Value
 
 
 class Base:
     def __init__(self, template, instance_id):
         self.template = template
-        self.topology = None  # Set once we are added to topology.
+
+        # Set once we are added to topology.
+        self.topology: Topology = None
 
         # Set attributes that all instances should have
         self.attributes = dict(
@@ -23,10 +26,9 @@ def reset_attributes(self):
         # data. Shared stuff is left in the template. We also make every
         # property into an attribute as TOSCA standard requires.
         self.attributes.update(
-            (k, v.copy()) for k, v in itertools.chain(
-                self.template.properties.items(),
-                self.template.attributes.items(),
-            ) if k not in ("tosca_name", "tosca_id", "state")
+            (k, v.copy())
+            for k, v in itertools.chain(self.template.properties.items(), self.template.attributes.items())
+            if k not in ("tosca_name", "tosca_id", "state")
         )
 
     def write(self):
@@ -63,9 +65,7 @@ def set_state(self, state, write=True):
             self.write()
 
     def run_operation(self, host, interface, operation, verbose, workdir):
-        success, outputs, attributes = self.template.run_operation(
-            host, interface, operation, self, verbose, workdir
-        )
+        success, outputs, attributes = self.template.run_operation(host, interface, operation, self, verbose, workdir)
 
         if not success:
             raise OperationError("Failed")
diff --git a/src/opera/instance/node.py b/src/opera/instance/node.py
index 7654f23d..1eb0348a 100644
--- a/src/opera/instance/node.py
+++ b/src/opera/instance/node.py
@@ -1,6 +1,6 @@
 from opera.error import DataError
-from .base import Base
 from opera.threading import utils as thread_utils
+from .base import Base
 
 
 class Node(Base):
@@ -11,7 +11,8 @@ def __init__(self, template, instance_id):
         self.out_edges = {}  # This is what we fill during the linking phase.
 
     def instantiate_relationships(self):
-        assert self.topology, "Cannot instantiate relationships"
+        if not self.topology:
+            raise AssertionError("Cannot instantiate relationships")
 
         for requirement in self.template.requirements:
             rname = requirement.name
@@ -63,43 +64,33 @@ def deploy(self, verbose, workdir):
         self.set_state("creating")
         self.run_operation("HOST", "Standard", "create", verbose, workdir)
         self.set_state("created")
-
         self.set_state("configuring")
-        for requirement in set([r.name for r in self.template.requirements]):
+
+        for requirement in set(r.name for r in self.template.requirements):
             for relationship in self.out_edges[requirement].values():
-                relationship.run_operation(
-                    "SOURCE", "Configure", "pre_configure_source", verbose,
-                    workdir
-                )
+                relationship.run_operation("SOURCE", "Configure", "pre_configure_source", verbose, workdir)
+
         for requirement_dependants in self.in_edges.values():
             for relationship in requirement_dependants.values():
-                relationship.run_operation(
-                    "TARGET", "Configure", "pre_configure_target", verbose,
-                    workdir
-                )
+                relationship.run_operation("TARGET", "Configure", "pre_configure_target", verbose, workdir)
+
         self.run_operation("HOST", "Standard", "configure", verbose, workdir)
-        for requirement in set([r.name for r in self.template.requirements]):
+
+        for requirement in set(r.name for r in self.template.requirements):
             for relationship in self.out_edges[requirement].values():
-                relationship.run_operation(
-                    "SOURCE", "Configure", "post_configure_source", verbose,
-                    workdir
-                )
+                relationship.run_operation("SOURCE", "Configure", "post_configure_source", verbose, workdir)
+
         for requirement_dependants in self.in_edges.values():
             for relationship in requirement_dependants.values():
-                relationship.run_operation(
-                    "TARGET", "Configure", "post_configure_target", verbose,
-                    workdir
-                )
-        self.set_state("configured")
+                relationship.run_operation("TARGET", "Configure", "post_configure_target", verbose, workdir)
 
+        self.set_state("configured")
         self.set_state("starting")
         self.run_operation("HOST", "Standard", "start", verbose, workdir)
         self.set_state("started")
 
         # TODO(@tadeboro): Execute various add hooks
-        thread_utils.print_thread(
-            "  Deployment of {} complete".format(self.tosca_id)
-        )
+        thread_utils.print_thread("  Deployment of {} complete".format(self.tosca_id))
 
     def undeploy(self, verbose, workdir):
         thread_utils.print_thread("  Undeploying {}".format(self.tosca_id))
@@ -117,9 +108,7 @@ def undeploy(self, verbose, workdir):
         self.reset_attributes()
         self.write()
 
-        thread_utils.print_thread(
-            "  Undeployment of {} complete".format(self.tosca_id)
-        )
+        thread_utils.print_thread("  Undeployment of {} complete".format(self.tosca_id))
 
     #
     # TOSCA functions
@@ -130,11 +119,9 @@ def get_attribute(self, params):
         if host == "HOST":
             raise DataError("HOST is not yet supported in opera.")
         if host != "SELF":
-            raise DataError(
-                "Attribute host should be set to 'SELF' which is the only "
-                "valid value. This is needed to indicate that the attribute "
-                "is referenced locally from something in the node itself."
-            )
+            raise DataError("Attribute host should be set to 'SELF' which is the only valid value. "
+                            "This is needed to indicate that the attribute is referenced locally from something "
+                            "in the node itself.")
 
         # TODO(@tadeboro): Add support for nested attribute values once we
         # have data type support.
@@ -142,21 +129,15 @@ def get_attribute(self, params):
             return self.attributes[attr].eval(self, attr)
 
         # Check if there are capability and requirement with the same name.
-        if attr in self.out_edges and attr in [c.name for c in
-                                               self.template.capabilities]:
-            raise DataError("There are capability and requirement with the "
-                            "same name: '{}'.".format(attr, ))
+        if attr in self.out_edges and attr in [c.name for c in self.template.capabilities]:
+            raise DataError("There are capability and requirement with the same name: '{}'.".format(attr, ))
 
         # If we have no attribute, try searching for capability.
-        capabilities = tuple(
-            c for c in self.template.capabilities if c.name == attr
-        )
+        capabilities = tuple(c for c in self.template.capabilities if c.name == attr)
         if len(capabilities) > 1:
-            raise DataError(
-                "More than one capability is named '{}'.".format(attr, ))
+            raise DataError("More than one capability is named '{}'.".format(attr, ))
 
-        if len(capabilities) == 1 and capabilities[0].attributes and len(
-                rest) != 0:
+        if len(capabilities) == 1 and capabilities[0].attributes and len(rest) != 0:
             return capabilities[0].attributes.get(rest[0]).data
 
         # If we have no attribute, try searching for requirement.
@@ -164,12 +145,8 @@ def get_attribute(self, params):
         if len(relationships) == 0:
             raise DataError("Cannot find attribute '{}'.".format(attr))
         if len(relationships) > 1:
-            raise DataError(
-                "Targeting more than one instance via '{}'.".format(attr),
-            )
-        return next(iter(relationships.values())).target.get_attribute(
-            ["SELF"] + rest,
-        )
+            raise DataError("Targeting more than one instance via '{}'.".format(attr))
+        return next(iter(relationships.values())).target.get_attribute(["SELF"] + rest)
 
     def get_property(self, params):
         return self.template.get_property(params)
@@ -178,16 +155,14 @@ def get_input(self, params):
         return self.template.get_input(params)
 
     def map_attribute(self, params, value):
-        host, attr, *rest = params
+        host, attr, *_ = params
 
         if host == "HOST":
             raise DataError("HOST is not yet supported in opera.")
         if host != "SELF":
-            raise DataError(
-                "Attribute host should be set to 'SELF' which is the only "
-                "valid value. This is needed to indicate that the attribute "
-                "is referenced locally from something in the node itself."
-            )
+            raise DataError("Attribute host should be set to 'SELF' which is the only valid value. "
+                            "This is needed to indicate that the attribute is referenced locally from something "
+                            "in the node itself.")
 
         # TODO(@tadeboro): Add support for nested attribute values once we
         # have data type support.
diff --git a/src/opera/instance/relationship.py b/src/opera/instance/relationship.py
index 3bd9ccbc..6d637ae2 100644
--- a/src/opera/instance/relationship.py
+++ b/src/opera/instance/relationship.py
@@ -1,6 +1,5 @@
 from opera.error import DataError
-
-from .base import Base
+from opera.instance.base import Base
 
 
 class Relationship(Base):
@@ -17,9 +16,7 @@ def get_attribute(self, params):
         host, attr, *rest = params
 
         if host not in ("SELF", "SOURCE", "TARGET"):
-            raise DataError(
-                "Attribute host should be set to 'SELF', 'SOURCE' or 'TARGET'."
-            )
+            raise DataError("Attribute host should be set to 'SELF', 'SOURCE' or 'TARGET'.")
 
         if host == "SOURCE":
             return self.source.get_attribute(["SELF", attr] + rest)
@@ -36,9 +33,7 @@ def get_property(self, params):
         host, prop, *rest = params
 
         if host not in ("SELF", "SOURCE", "TARGET"):
-            raise DataError(
-                "Property host should be set to 'SELF', 'SOURCE' or 'TARGET'."
-            )
+            raise DataError("Property host should be set to 'SELF', 'SOURCE' or 'TARGET'.")
 
         if host == "SOURCE":
             return self.source.get_property(["SELF", prop] + rest)
@@ -53,9 +48,7 @@ def map_attribute(self, params, value):
         host, attr, *rest = params
 
         if host not in ("SELF", "SOURCE", "TARGET"):
-            raise DataError(
-                "Attribute host should be set to 'SELF', 'SOURCE' or 'TARGET'."
-            )
+            raise DataError("Attribute host should be set to 'SELF', 'SOURCE' or 'TARGET'.")
 
         if host == "SOURCE":
             self.source.map_attribute(["SELF", attr] + rest, value)
@@ -68,9 +61,7 @@ def get_artifact(self, params):
         host, prop, *rest = params
 
         if host not in ("SELF", "SOURCE", "TARGET"):
-            raise DataError(
-                "Artifact host should be set to 'SELF', 'SOURCE' or 'TARGET'."
-            )
+            raise DataError("Artifact host should be set to 'SELF', 'SOURCE' or 'TARGET'.")
 
         if host == "SOURCE":
             return self.source.get_property(["SELF", prop] + rest)
diff --git a/src/opera/instance/topology.py b/src/opera/instance/topology.py
index 111942a9..0eefeb3a 100644
--- a/src/opera/instance/topology.py
+++ b/src/opera/instance/topology.py
@@ -21,9 +21,8 @@ def get_info(self):
         return "interrupted"
 
     def deploy(self, verbose, workdir, num_workers=None):
-        # Currently, we are running a really stupid O(n^3) algorithm, but
-        # unless we get to the templates with millions of node instances, we
-        # should be fine.
+        # Currently, we are running a really stupid O(n^3) algorithm, but unless we get to the templates with
+        # millions of node instances, we should be fine.
         with NodeExecutor(num_workers) as executor:
             do_deploy = True
             while do_deploy:
@@ -31,14 +30,12 @@ def deploy(self, verbose, workdir, num_workers=None):
                     if (not node.deployed
                             and node.ready_for_deploy
                             and executor.can_submit(node.tosca_id)):
-                        executor.submit_operation(node.deploy, node.tosca_id,
-                                                  verbose, workdir)
+                        executor.submit_operation(node.deploy, node.tosca_id, verbose, workdir)
                 do_deploy = executor.wait_results()
 
     def undeploy(self, verbose, workdir, num_workers=None):
-        # Currently, we are running a really stupid O(n^3) algorithm, but
-        # unless we get to the templates with millions of node instances, we
-        # should be fine.
+        # Currently, we are running a really stupid O(n^3) algorithm, but  unless we get to the templates with
+        # millions of node instances, we should be fine.
         with NodeExecutor(num_workers) as executor:
             do_undeploy = True
             while do_undeploy:
@@ -46,8 +43,7 @@ def undeploy(self, verbose, workdir, num_workers=None):
                     if (not node.undeployed
                             and node.ready_for_undeploy
                             and executor.can_submit(node.tosca_id)):
-                        executor.submit_operation(node.undeploy, node.tosca_id,
-                                                  verbose, workdir)
+                        executor.submit_operation(node.undeploy, node.tosca_id, verbose, workdir)
                 do_undeploy = executor.wait_results()
 
     def write(self, data, instance_id):
diff --git a/src/opera/parser/tosca/__init__.py b/src/opera/parser/tosca/__init__.py
index 706938c1..2e61768e 100644
--- a/src/opera/parser/tosca/__init__.py
+++ b/src/opera/parser/tosca/__init__.py
@@ -1,11 +1,10 @@
-from pathlib import PurePath
 import importlib
+from pathlib import PurePath
 
 from opera import stdlib
 from opera.error import ParseError
 from opera.parser import yaml
 
-
 SUPPORTED_VERSIONS = dict(
     tosca_simple_yaml_1_3="v_1_3",
 )
@@ -15,20 +14,14 @@ def load(base_path, template_name):
     with (base_path / template_name).open() as input_fd:
         input_yaml = yaml.load(input_fd, str(template_name))
     if not isinstance(input_yaml.value, dict):
-        raise ParseError(
-            "Top level structure should be a map.", yaml_node.loc,
-        )
+        raise ParseError("Top level structure should be a map.", "0:0")
 
     tosca_version = _get_tosca_version(input_yaml)
     parser = _get_parser(tosca_version)
 
     stdlib_yaml = stdlib.load(tosca_version)
-    service = parser.parse(
-        stdlib_yaml, base_path, PurePath("STDLIB"), set(),
-    )[0]
-    service.merge(parser.parse(
-        input_yaml, base_path, template_name, set(),
-    )[0])
+    service = parser.parse_service_template(stdlib_yaml, base_path, PurePath("STDLIB"), set())[0]
+    service.merge(parser.parse_service_template(input_yaml, base_path, template_name, set())[0])
     service.visit("resolve_path", base_path)
     service.visit("resolve_reference", service)
 
@@ -36,7 +29,7 @@ def load(base_path, template_name):
 
 
 def _get_parser(tosca_version):
-    return importlib.import_module(".v_1_3", __name__).Parser
+    return importlib.import_module(".v_1_3", __name__).Parser  # type: ignore
 
 
 def _get_tosca_version(input_yaml):
@@ -44,11 +37,8 @@ def _get_tosca_version(input_yaml):
         if k.value == "tosca_definitions_version":
             try:
                 return SUPPORTED_VERSIONS[v.value]
-            except (TypeError, KeyError):
-                raise ParseError(
-                    "Invalid TOSCA version. Available: {}.".format(
-                        ", ".join(SUPPORTED_VERSIONS.keys()),
-                    ), v.loc,
-                )
+            except (TypeError, KeyError) as e:
+                raise ParseError("Invalid TOSCA version. Available: {}.".format(", ".join(SUPPORTED_VERSIONS.keys())),
+                                 v.loc) from e
 
     raise ParseError("Missing TOSCA version", input_yaml.loc)
diff --git a/src/opera/parser/tosca/csar.py b/src/opera/parser/tosca/csar.py
index f6148399..3c6b655a 100644
--- a/src/opera/parser/tosca/csar.py
+++ b/src/opera/parser/tosca/csar.py
@@ -2,7 +2,7 @@
 import traceback
 from abc import ABC, abstractmethod
 from pathlib import Path, PurePath
-from tempfile import mktemp
+from tempfile import TemporaryDirectory
 from typing import List, IO, Optional
 from zipfile import ZipFile
 
@@ -27,9 +27,8 @@ class CsarMeta:
     REQUIRED_KEYS = {KEY_TOSCA_META_FILE_VERSION, KEY_CSAR_VERSION,
                      KEY_CREATED_BY}
 
-    def __init__(self, name: str, content_type: str,
-                 tosca_meta_file_version: str,
-                 csar_version: str, created_by: str, entry_definitions: str):
+    def __init__(self, name: Optional[str], content_type: Optional[str], tosca_meta_file_version: str,
+                 csar_version: str, created_by: str, entry_definitions: Optional[str]):
         self.name = name
         self.content_type = content_type
         self.tosca_meta_file_version = tosca_meta_file_version
@@ -39,14 +38,12 @@ def __init__(self, name: str, content_type: str,
 
     @classmethod
     def parse(cls, contents: str) -> "CsarMeta":
-        # FIXME: the meta format is not yaml, but it's close enough to parse a
-        #        simple file
+        # FIXME: the meta format is not yaml, but it"s close enough to parse a simple file
         parsed = yaml.safe_load(contents)
 
         for req in CsarMeta.REQUIRED_KEYS:
             if req not in parsed:
-                raise ParseError("Missing required meta entry: {}".format(req),
-                                 CsarMeta.METADATA_PATH)
+                raise ParseError("Missing required meta entry: {}".format(req), CsarMeta.METADATA_PATH)
 
         csar_version = str(parsed[CsarMeta.KEY_CSAR_VERSION])
         if csar_version not in CsarMeta.SUPPORTED_CSAR_VERSIONS:
@@ -81,16 +78,13 @@ def render(self) -> str:
         ordered_fields = [
             (CsarMeta.KEY_NAME, self.name),
             (CsarMeta.KEY_CONTENT_TYPE, self.content_type),
-            (
-                CsarMeta.KEY_TOSCA_META_FILE_VERSION,
-                self.tosca_meta_file_version),
+            (CsarMeta.KEY_TOSCA_META_FILE_VERSION, self.tosca_meta_file_version),
             (CsarMeta.KEY_CSAR_VERSION, self.csar_version),
             (CsarMeta.KEY_CREATED_BY, self.created_by),
             (CsarMeta.KEY_ENTRY_DEFINITIONS, self.entry_definitions)
         ]
 
-        return "\n".join(
-            "{}: {}".format(k, v) for k, v in ordered_fields if v is not None)
+        return "\n".join("{}: {}".format(k, v) for k, v in ordered_fields if v is not None)
 
 
 class ServiceTemplateMeta:
@@ -114,9 +108,7 @@ def parse(cls, contents: str) -> "ServiceTemplateMeta":
 
         for req in ServiceTemplateMeta.REQUIRED_KEYS:
             if req not in parsed["metadata"]:
-                raise ParseError(
-                    "Missing required service template meta entry: "
-                    "metadata. {}".format(req), "")
+                raise ParseError("Missing required service template meta entry: metadata. {}".format(req), "")
 
         return ServiceTemplateMeta(
             name=parsed["metadata"][ServiceTemplateMeta.KEY_NAME],
@@ -144,49 +136,44 @@ def create(cls, path: PurePath) -> "CloudServiceArchive":
             raise OperaError("CSARs are either regular files or directories.")
 
     @abstractmethod
-    def package_csar(self, output, service_template=None, csar_format="zip"):
+    def package_csar(self, output_file, service_template=None, csar_format="zip") -> str:
         pass
 
     @abstractmethod
-    def unpackage_csar(self, output):
+    def unpackage_csar(self, output_dir):
         pass
 
     @abstractmethod
     def members(self) -> List[PurePath]:
         """
-        Get a list of files and directories with paths relative to the root of
-        the CSAR. Absolute paths not allowed.
+        Get a list of files and directories with paths relative to the root of the CSAR.
+
+        Absolute paths not allowed.
         """
-        pass
 
     @abstractmethod
     def open_member(self, path: PurePath) -> IO:
-        """
-        Opens a read-only stream for the file at the specified path.
-        """
-        pass
+        """Open a read-only stream for the file at the specified path."""
 
     @abstractmethod
     def _member_exists(self, member: PurePath) -> bool:
-        """
-        Verifies whether the member file exists.
-        """
-        pass
+        """Verify whether the member file exists."""
 
     @abstractmethod
     def _member_is_dir(self, member: PurePath) -> bool:
         """
-        Assumes the path, relative to the CSAR root, exists, and returns
-         whether it is a directory.
+        Check whether the member is a directory.
+
+        Assumes the path, relative to the CSAR root, exists, and returns whether it is a directory.
         Symlinks are resolved.
         """
-        pass
 
     @abstractmethod
     def _member_is_file(self, member: PurePath) -> bool:
         """
-        Assumes the path, relative to the CSAR root, exists, and returns
-         whether it is a regular file.
+        Check whether the member is a file.
+
+        Assumes the path, relative to the CSAR root, exists, and returns whether it is a regular file.
         Symlinks are resolved.
         """
 
@@ -197,28 +184,22 @@ def validate_csar(self):
 
         if not contains_meta:
             if not contains_single_root_yaml:
-                raise OperaError(
-                    "When metadata is not present, there should be exactly "
-                    "one root level YAML file "
-                    "in the root of the CSAR. Files found: {}.".format(
-                        str(root_yaml_files)))
+                raise OperaError("When metadata is not present, there should be exactly one root level YAML file in "
+                                 "the root of the CSAR. Files found: {}.".format(str(root_yaml_files)))
 
             try:
                 self.parse_service_template_meta(root_yaml_files[0])
             except ParseError as e:
-                raise OperaError(
-                    "When metadata is not present, the single root level YAML"
-                    "file "
-                    "must contain metadata: {}".format(str(e)))
+                raise OperaError("When metadata is not present, the single root level YAML file must contain "
+                                 "metadata: {}".format(str(e))) from e
 
         meta = self.parse_csar_meta()
-        if meta.entry_definitions is not None:
-            # check if 'Entry-Definitions' points to an existing
+        if meta is not None and meta.entry_definitions is not None:
+            # check if "Entry-Definitions" points to an existing
             # template file in the CSAR
             if not self._member_exists(PurePath(meta.entry_definitions)):
                 raise OperaError("{} defined with Entry-Definitions in {} "
-                                 "does not exist.".format(
-                    meta.entry_definitions, CsarMeta.METADATA_PATH))
+                                 "does not exist.".format(meta.entry_definitions, CsarMeta.METADATA_PATH))
 
     def parse_csar_meta(self) -> Optional[CsarMeta]:
         path = PurePath(CsarMeta.METADATA_PATH)
@@ -230,8 +211,7 @@ def parse_csar_meta(self) -> Optional[CsarMeta]:
 
         return CsarMeta.parse(contents)
 
-    def parse_service_template_meta(self, service_template_path: PurePath) -> \
-            Optional[ServiceTemplateMeta]:
+    def parse_service_template_meta(self, service_template_path: PurePath) -> Optional[ServiceTemplateMeta]:
         if not self._member_exists(service_template_path):
             return None
 
@@ -242,14 +222,12 @@ def parse_service_template_meta(self, service_template_path: PurePath) -> \
 
     def get_root_yaml_files(self) -> List[PurePath]:
         all_files = self.members()
-        result = [f for f in all_files if
-                  len(f.parts) == 1 and (
-                          f.match("*.yaml") or f.match("*.yml"))]
+        result = [f for f in all_files if len(f.parts) == 1 and (f.match("*.yaml") or f.match("*.yml"))]
         return result
 
     def get_entrypoint(self) -> Optional[PurePath]:
         meta = self.parse_csar_meta()
-        if meta.entry_definitions is not None:
+        if meta is not None and meta.entry_definitions is not None:
             return PurePath(meta.entry_definitions)
 
         root_yamls = self.get_root_yaml_files()
@@ -259,13 +237,12 @@ def get_entrypoint(self) -> Optional[PurePath]:
 class FileCloudServiceArchive(CloudServiceArchive):
     def __init__(self, csar_file: Path):
         """csar_file is guaranteed to exist, be absolute, and be a file."""
-        super(FileCloudServiceArchive, self).__init__(str(csar_file.name))
+        super().__init__(str(csar_file.name))
         self.csar_file = csar_file
         self.backing_zip = ZipFile(csar_file, mode="r")
 
-    def package_csar(self, output, service_template=None, csar_format="zip"):
-        raise NotImplementedError(
-            "Repackaging a packaged CSAR is not implemented.")
+    def package_csar(self, output_file, service_template=None, csar_format="zip") -> str:
+        raise NotImplementedError("Repackaging a packaged CSAR is not implemented.")
 
     def unpackage_csar(self, output_dir):
         csar_format = determine_archive_format(str(self.csar_file))
@@ -286,8 +263,9 @@ def _member_exists(self, member: PurePath) -> bool:
 
     def _member_is_dir(self, member: PurePath) -> bool:
         return next(
-            zi for zi in self.backing_zip.infolist() if
-            zi.filename.rstrip("/") == member.name.rstrip("/")).is_dir()
+            zi for zi in self.backing_zip.infolist()
+            if zi.filename.rstrip("/") == member.name.rstrip("/")
+        ).is_dir()
 
     def _member_is_file(self, member: PurePath) -> bool:
         return not self._member_is_dir(member)
@@ -296,11 +274,10 @@ def _member_is_file(self, member: PurePath) -> bool:
 class DirCloudServiceArchive(CloudServiceArchive):
     def __init__(self, csar_dir: Path):
         """csar_dir is guaranteed to exist and be a file."""
-        super(DirCloudServiceArchive, self).__init__(str(csar_dir.name))
+        super().__init__(str(csar_dir.name))
         self.csar_dir = csar_dir
 
-    def package_csar(self, output_file: str, service_template: str = None,
-                     csar_format: str = "zip"):
+    def package_csar(self, output_file: str, service_template: str = None, csar_format: str = "zip") -> str:
         meta = self.parse_csar_meta()
 
         try:
@@ -308,76 +285,57 @@ def package_csar(self, output_file: str, service_template: str = None,
                 root_yaml_files = self.get_root_yaml_files()
 
                 if meta is None and len(root_yaml_files) != 1:
-                    raise ParseError(
-                        "You didn't specify the CSAR TOSCA entrypoint with "
-                        "'-t/--service-template' option. Therefore there "
-                        "should be one YAML file in the root of the CSAR to "
-                        "select it as the entrypoint. More than one YAML has "
-                        "been found: {}. Please select one of the files as "
-                        "the CSAR entrypoint using '-t/--service-template' "
-                        "flag or remove all the excessive YAML files.".format(
-                            list(map(str, root_yaml_files))), self)
+                    raise ParseError("You didn't specify the CSAR TOSCA entrypoint with '-t/--service-template' "
+                                     "option. Therefore there should be one YAML file in the root of the CSAR to "
+                                     "select it as the entrypoint. More than one YAML has been found: {}. Please "
+                                     "select one of the files as the CSAR entrypoint using '-t/--service-template' "
+                                     "flag or remove all the excessive YAML files."
+                                     .format(list(map(str, root_yaml_files))), self)
                 service_template = root_yaml_files[0].name
             else:
                 if not self._member_exists(PurePath(service_template)):
-                    raise ParseError('The supplied TOSCA service template '
-                                     'file "{}" does not exist in folder '
-                                     '"{}".'.format(service_template,
-                                                    self.csar_dir), self)
+                    raise ParseError("The supplied TOSCA service template file '{}' does not exist in folder '{}'."
+                                     .format(service_template, self.csar_dir), self)
 
             meta = self.parse_csar_meta()
             if meta is not None:
 
                 template_entry = meta.entry_definitions
                 if service_template and template_entry != service_template:
-                    raise ParseError('The file entry "{}" defined within '
-                                     '"Entry-Definitions" in '
-                                     '"TOSCA-Metadata/TOSCA.meta" does not '
-                                     'match with the file name "{}" supplied '
-                                     'in service_template CLI argument.'.
-                                     format(template_entry, service_template),
-                                     self)
-
-                # check if 'Entry-Definitions' points to an existing
+                    raise ParseError("The file entry '{}' defined within 'Entry-Definitions' in "
+                                     "'TOSCA-Metadata/TOSCA.meta' does not match with the file name '{}' supplied "
+                                     "in service_template CLI argument.".format(template_entry, service_template), self)
+
+                # check if "Entry-Definitions" points to an existing
                 # template file in the CSAR
-                if not self._member_exists(PurePath(template_entry)):
-                    raise ParseError('The file "{}" defined within '
-                                     '"Entry-Definitions" in '
-                                     '"TOSCA-Metadata/TOSCA.meta" does '
-                                     'not exist.'.format(template_entry), self)
-                return shutil.make_archive(output_file, csar_format,
-                                           self.csar_dir)
+                if template_entry is not None and not self._member_exists(PurePath(template_entry)):
+                    raise ParseError("The file '{}' defined within 'Entry-Definitions' in 'TOSCA-Metadata/TOSCA.meta' "
+                                     "does not exist.".format(template_entry), self)
+                return shutil.make_archive(output_file, csar_format, self.csar_dir)
             else:
-                # use tempdir because we don't want to modify user's folder
-                # with TemporaryDirectory(prefix="opera-package-") as tempdir
-                # cannot be used because shutil.copytree would fail due to the
-                # existing temporary folder (this happens only when running
-                # with python version lower than 3.8)
-                tempdir = mktemp(prefix="opera-package-")
-                # create tempdir and copy in all the needed CSAR files
-                shutil.copytree(self.csar_dir, tempdir)
-
-                # create TOSCA-Metadata/TOSCA.meta file using the specified
-                # TOSCA service template or directory root YAML file
-                content = ("TOSCA-Meta-File-Version: 1.1\n"
-                           "CSAR-Version: 1.1\n"
-                           "Created-By: xOpera TOSCA orchestrator\n"
-                           "Entry-Definitions: {}\n").format(service_template)
-
-                meta_file_folder = Path(tempdir) / "TOSCA-Metadata"
-                meta_file = (meta_file_folder / "TOSCA.meta")
-
-                meta_file_folder.mkdir()
-                meta_file.touch()
-                meta_file.write_text(content)
-
-                return shutil.make_archive(output_file, csar_format, tempdir)
-        except Exception:
-            raise ParseError(
-                "Error creating CSAR:\n{}".format(traceback.format_exc()),
-                self)
+                with TemporaryDirectory(prefix="opera-package-") as tempdir:
+                    extract_path = Path(tempdir) / "extract"
+                    shutil.copytree(self.csar_dir, extract_path)
+
+                    # create TOSCA-Metadata/TOSCA.meta file using the specified
+                    # TOSCA service template or directory root YAML file
+                    content = ("TOSCA-Meta-File-Version: 1.1\n"
+                               "CSAR-Version: 1.1\n"
+                               "Created-By: xOpera TOSCA orchestrator\n"
+                               "Entry-Definitions: {}\n").format(service_template)
 
-    def unpackage_csar(self, output_dir, csar_format="zip"):
+                    meta_file_folder = extract_path / "TOSCA-Metadata"
+                    meta_file = (meta_file_folder / "TOSCA.meta")
+
+                    meta_file_folder.mkdir()
+                    meta_file.touch()
+                    meta_file.write_text(content)
+
+                    return shutil.make_archive(output_file, csar_format, extract_path)
+        except Exception as e:  # noqa: W0703
+            raise ParseError("Error creating CSAR:\n{}".format(traceback.format_exc()), self) from e
+
+    def unpackage_csar(self, output_dir):
         raise OperaError("Cannot unpackage a directory-based CSAR.")
 
     def members(self) -> List[PurePath]:
diff --git a/src/opera/parser/tosca/entity.py b/src/opera/parser/tosca/entity.py
index bb07c95d..1f01037c 100644
--- a/src/opera/parser/tosca/entity.py
+++ b/src/opera/parser/tosca/entity.py
@@ -1,17 +1,26 @@
+from typing import Optional, Set, Dict, Type, Union
+
+from .base import Base
+from .list import List
 from .map import Map, MapWrapper
-from .reference import Reference
+from .reference import Reference, ReferenceXOR
 from .string import String
 from .version import Version
 
 
 class Entity(MapWrapper):
-    ATTRS = {}  # This must be overridden in derived classes
-    REQUIRED = set()  # This can be overriden in derived classes
+    # This must be overridden in derived classes
+    ATTRS: Dict[str, Union[Type[Base], Base, Map, List, Reference, ReferenceXOR]] = {}
+
+    # This can be overridden in derived classes
+    REQUIRED: Set[str] = set()
 
     @classmethod
     def validate(cls, yaml_node):
-        assert cls.ATTRS != {}
-        assert isinstance(cls.REQUIRED, set)
+        if cls.ATTRS == {}:
+            raise AssertionError()
+        if not isinstance(cls.REQUIRED, set):
+            raise AssertionError()
 
         if not isinstance(yaml_node.value, dict):
             cls.abort("Expected map.", yaml_node.loc)
@@ -24,17 +33,11 @@ def validate(cls, yaml_node):
 
         missing_keys = cls.REQUIRED - data_keys
         if missing_keys:
-            cls.abort(
-                "Missing required fields: {}".format(", ".join(missing_keys)),
-                yaml_node.loc,
-            )
+            cls.abort("Missing required fields: {}".format(", ".join(missing_keys)), yaml_node.loc)
 
         extra_keys = data_keys - cls.attrs().keys()
         if extra_keys:
-            cls.abort(
-                "Invalid keys: {}".format(", ".join(extra_keys)),
-                yaml_node.loc,
-            )
+            cls.abort("Invalid keys: {}".format(", ".join(extra_keys)), yaml_node.loc)
 
     @classmethod
     def build(cls, yaml_node):
@@ -52,12 +55,12 @@ def attrs(cls):
     def __getattr__(self, key):
         try:
             return self.data[key]
-        except KeyError:
-            raise AttributeError(key)
+        except KeyError as e:
+            raise AttributeError(key) from e
 
 
 class TypeEntity(Entity):
-    REFERENCE = None  # Override in subclasses
+    REFERENCE: Optional[Reference] = None  # Override in subclasses
 
     @classmethod
     def validate(cls, yaml_node):
@@ -69,8 +72,8 @@ def validate(cls, yaml_node):
 
     @classmethod
     def attrs(cls):
-        assert isinstance(cls.REFERENCE, Reference), \
-            "Override REFERENCE in {} with Reference.".format(cls.__name__)
+        if not isinstance(cls.REFERENCE, Reference):
+            raise AssertionError("Override REFERENCE in {} with Reference.".format(cls.__name__))
 
         attributes = cls.ATTRS.copy()
         attributes.update(
diff --git a/src/opera/parser/tosca/integer.py b/src/opera/parser/tosca/integer.py
index 327aa137..b399648b 100644
--- a/src/opera/parser/tosca/integer.py
+++ b/src/opera/parser/tosca/integer.py
@@ -5,8 +5,5 @@ class Integer(Comparable):
     @classmethod
     def validate(cls, yaml_node):
         super().validate(yaml_node)
-        if (
-                not isinstance(yaml_node.value, int) or
-                isinstance(yaml_node.value, bool)
-        ):
+        if not isinstance(yaml_node.value, int) or isinstance(yaml_node.value, bool):
             cls.abort("Expected integer.", yaml_node.loc)
diff --git a/src/opera/parser/tosca/list.py b/src/opera/parser/tosca/list.py
index a4d1350e..dd03e6d4 100644
--- a/src/opera/parser/tosca/list.py
+++ b/src/opera/parser/tosca/list.py
@@ -1,6 +1,5 @@
 from opera.error import ParseError
-
-from .base import Base
+from opera.parser.tosca.base import Base
 
 
 class ListWrapper(Base):
@@ -30,6 +29,4 @@ def parse(self, yaml_node):
         if not isinstance(yaml_node.value, list):
             raise ParseError("Expected list.", yaml_node.loc)
 
-        return ListWrapper([
-            self.value_class.parse(v) for v in yaml_node.value
-        ], yaml_node.loc)
+        return ListWrapper([self.value_class.parse(v) for v in yaml_node.value], yaml_node.loc)
diff --git a/src/opera/parser/tosca/map.py b/src/opera/parser/tosca/map.py
index 7749f4d1..4d151bf5 100644
--- a/src/opera/parser/tosca/map.py
+++ b/src/opera/parser/tosca/map.py
@@ -2,7 +2,6 @@
 
 from opera.error import ParseError
 from opera.parser.yaml.node import Node
-
 from .base import Base
 
 
@@ -35,11 +34,8 @@ def dig(self, key, *subpath):
     def merge(self, other):
         duplicates = set(self.keys()) & set(other.keys())
         if duplicates:
-            self.abort(
-                "Duplicate keys '{}' found in {} and {}".format(
-                    ", ".join(duplicates), self.loc, other.loc,
-                ), self.loc,
-            )
+            self.abort("Duplicate keys '{}' found in {} and {}".format(", ".join(duplicates), self.loc, other.loc),
+                       self.loc)
         self.data.update(other.data)
 
     def visit(self, method, *args, **kwargs):
@@ -57,7 +53,7 @@ def parse(self, yaml_node):
 
         for k in yaml_node.value:
             if not isinstance(k.value, str):
-                cls.abort("Expected string key.", k.loc)
+                ParseError("Expected string key.", k.loc)
 
         return MapWrapper(collections.OrderedDict(
             (k.value, self.value_class.parse(v))
@@ -68,9 +64,7 @@ def parse(self, yaml_node):
 class OrderedMap(Map):
     def parse(self, yaml_node):
         if not isinstance(yaml_node.value, list):
-            raise ParseError(
-                "Expected list of single-key maps.", yaml_node.loc,
-            )
+            raise ParseError("Expected list of single-key maps.", yaml_node.loc)
 
         data = collections.OrderedDict()
         for item in yaml_node.value:
diff --git a/src/opera/parser/tosca/path.py b/src/opera/parser/tosca/path.py
index 4102d467..5d9dbc24 100644
--- a/src/opera/parser/tosca/path.py
+++ b/src/opera/parser/tosca/path.py
@@ -63,6 +63,4 @@ def _validate_path(self, base_path):
         if abs_path.is_symlink():
             self.abort("Path {} is a symlink.".format(abs_path), self.loc)
         if not abs_path.is_dir() and not abs_path.is_file():
-            self.abort(
-                "Path {} is not file or folder.".format(abs_path), self.loc,
-            )
+            self.abort("Path {} is not file or folder.".format(abs_path), self.loc)
diff --git a/src/opera/parser/tosca/reference.py b/src/opera/parser/tosca/reference.py
index 21709fe5..0a63b857 100644
--- a/src/opera/parser/tosca/reference.py
+++ b/src/opera/parser/tosca/reference.py
@@ -1,3 +1,5 @@
+from typing import Tuple
+
 from .string import String
 from .type import Type
 
@@ -5,10 +7,11 @@
 class ReferenceWrapper(String):
     def __init__(self, data, loc):
         super().__init__(data, loc)
-        self.section_path = ()
+        self.section_path: Tuple = ()
 
     def resolve_reference(self, service_template):
-        assert self.section_path, "Missing section path"
+        if len(self.section_path) == 0:
+            raise AssertionError("Missing section path")
 
         # Special case for root types that should have no parent
         if self.data == "tosca.entity.Root":
@@ -16,9 +19,7 @@ def resolve_reference(self, service_template):
 
         target = service_template.dig(*self.section_path, self.data)
         if not target:
-            self.abort("Invalid reference {}".format(
-                "/".join(self.section_path + (self.data,)),
-            ), self.loc)
+            self.abort("Invalid reference {}".format("/".join(self.section_path + (self.data,))), self.loc)
 
         return target
 
@@ -33,10 +34,11 @@ def resolve_reference(self, service_template):
 class MultipleReferenceWrapper(String):
     def __init__(self, data, loc):
         super().__init__(data, loc)
-        self.section_paths = ()
+        self.section_paths: Tuple = ()
 
     def resolve_reference(self, service_template):
-        assert self.section_paths, "Missing section path"
+        if len(self.section_paths) == 0:
+            raise AssertionError("Missing section path")
 
         # Special case for root types that should have no parent
         if self.data == "tosca.entity.Root":
@@ -58,14 +60,15 @@ def resolve_reference(self, service_template):
         if len(targets) > 1:
             self.abort(
                 "Duplicate policy targets names were found: {}. Try to use unique names.".format(
-                    str(['/'.join(path_tuple) + "/" + str(self.data) for path_tuple in self.section_paths])
+                    str(["/".join(path_tuple) + "/" + str(self.data) for path_tuple in self.section_paths])
                 ), self.loc)
 
         if not path_exists:
             self.abort("Invalid reference, {} is not in {}".format(
-                str(self.data), str(
-                    ['/'.join(path_tuple) if isinstance(path_tuple, tuple) else path_tuple for path_tuple in
-                     self.section_paths])), self.loc)
+                str(self.data),
+                str(["/".join(path_tuple) if isinstance(path_tuple, tuple) else path_tuple
+                     for path_tuple in self.section_paths])
+            ), self.loc)
         return target_result
 
 
@@ -73,10 +76,12 @@ class Reference:
     WRAPPER_CLASS = ReferenceWrapper
 
     def __init__(self, *section_path):
-        assert section_path, "Section path should not be empty"
+        if not section_path:
+            raise AssertionError("Section path should not be empty")
+
         for part in section_path:
-            assert isinstance(part, str), \
-                "Section path parts should be strings."
+            if not isinstance(part, str):
+                raise AssertionError("Section path parts should be strings.")
 
         self.section_path = section_path
 
@@ -90,7 +95,8 @@ class ReferenceXOR:
     WRAPPER_CLASS = MultipleReferenceWrapper
 
     def __init__(self, *references):
-        assert references, "References should not be empty"
+        if not references:
+            raise AssertionError("References should not be empty")
         self.references = references
 
     def parse(self, yaml_node):
diff --git a/src/opera/parser/tosca/v_1_3/__init__.py b/src/opera/parser/tosca/v_1_3/__init__.py
index af0149ce..492ea719 100644
--- a/src/opera/parser/tosca/v_1_3/__init__.py
+++ b/src/opera/parser/tosca/v_1_3/__init__.py
@@ -1,4 +1,3 @@
 from .service_template import ServiceTemplate
 
-
 Parser = ServiceTemplate
diff --git a/src/opera/parser/tosca/v_1_3/activity_definition.py b/src/opera/parser/tosca/v_1_3/activity_definition.py
index a93f7223..1317abfa 100644
--- a/src/opera/parser/tosca/v_1_3/activity_definition.py
+++ b/src/opera/parser/tosca/v_1_3/activity_definition.py
@@ -1,12 +1,19 @@
+from typing import Dict, Union, Type
+
 from .parameter_definition import ParameterDefinition
+from ..base import Base
 from ..entity import Entity
+from ..list import List
 from ..map import Map
+from ..reference import Reference, ReferenceXOR
 from ..string import String
 from ..void import Void
 
+T_ATTR = Dict[str, Union[Type[Base], Base, Map, List, Reference, ReferenceXOR]]
+
 
 class ActivityDefinition(Entity):
-    ATTRS = dict()
+    ATTRS: T_ATTR = dict()
 
     @classmethod
     def validate(cls, yaml_node):
@@ -25,7 +32,7 @@ def validate(cls, yaml_node):
 
 
 class DelegateWorkflowActivityDefinition(Entity):
-    ATTRS = dict(
+    ATTRS: T_ATTR = dict(
         delegate=Void,
         workflow=String,
         inputs=Map(ParameterDefinition),
@@ -34,14 +41,14 @@ class DelegateWorkflowActivityDefinition(Entity):
 
 
 class SetStateActivityDefinition(Entity):
-    ATTRS = dict(
+    ATTRS: T_ATTR = dict(
         set_state=Void,
     )
     REQUIRED = {"set_state"}
 
 
 class CallOperationActivityDefinition(Entity):
-    ATTRS = dict(
+    ATTRS: T_ATTR = dict(
         call_operation=Void,
         operation=String,
         inputs=Map(ParameterDefinition),
@@ -50,7 +57,7 @@ class CallOperationActivityDefinition(Entity):
 
 
 class InlineWorkflowActivityDefinition(Entity):
-    ATTRS = dict(
+    ATTRS: T_ATTR = dict(
         inline=Void,
         workflow=String,
         inputs=Map(ParameterDefinition),
diff --git a/src/opera/parser/tosca/v_1_3/artifact_definition.py b/src/opera/parser/tosca/v_1_3/artifact_definition.py
index b966cb8b..08480dcf 100644
--- a/src/opera/parser/tosca/v_1_3/artifact_definition.py
+++ b/src/opera/parser/tosca/v_1_3/artifact_definition.py
@@ -1,8 +1,7 @@
-from opera.parser.yaml.node import Node
-from opera.value import Value
-
 import yaml
 
+from opera.parser.yaml.node import Node
+from opera.value import Value
 from ..entity import Entity
 from ..map import Map
 from ..path import Path
@@ -43,7 +42,6 @@ def get_value(self, typ):
             return Value(typ, True, yaml_data)
         return Value(typ, False)
 
-    def get_value_type(self, service_ast):
+    def get_value_type(self, service_ast):  # pylint: disable=no-self-use
         # TODO(@tadeboro): Implement types later.
         return None
-
diff --git a/src/opera/parser/tosca/v_1_3/artifact_type.py b/src/opera/parser/tosca/v_1_3/artifact_type.py
index d8a96e0c..8de8a89c 100644
--- a/src/opera/parser/tosca/v_1_3/artifact_type.py
+++ b/src/opera/parser/tosca/v_1_3/artifact_type.py
@@ -1,11 +1,10 @@
+from .property_definition import PropertyDefinition
 from ..entity import TypeEntity
 from ..list import List
 from ..map import Map
 from ..reference import Reference
 from ..string import String
 
-from .property_definition import PropertyDefinition
-
 
 class ArtifactType(TypeEntity):
     REFERENCE = Reference("artifact_types")
diff --git a/src/opera/parser/tosca/v_1_3/attribute_definition.py b/src/opera/parser/tosca/v_1_3/attribute_definition.py
index 380a5383..ae026147 100644
--- a/src/opera/parser/tosca/v_1_3/attribute_definition.py
+++ b/src/opera/parser/tosca/v_1_3/attribute_definition.py
@@ -1,13 +1,11 @@
 from opera.value import Value
-
+from .schema_definition import SchemaDefinition
+from .status import Status
 from ..entity import Entity
 from ..reference import DataTypeReference
 from ..string import String
 from ..void import Void
 
-from .schema_definition import SchemaDefinition
-from .status import Status
-
 
 class AttributeDefinition(Entity):
     ATTRS = dict(
@@ -25,6 +23,6 @@ def get_value(self, typ):
             return self.default.get_value(typ)
         return Value(typ, False)
 
-    def get_value_type(self, service_ast):
+    def get_value_type(self, service_ast):  # pylint: disable=no-self-use
         # TODO(@tadeboro): Implement type checks later.
         return None
diff --git a/src/opera/parser/tosca/v_1_3/capability_assignment.py b/src/opera/parser/tosca/v_1_3/capability_assignment.py
index 01bb039d..80ba1eb3 100644
--- a/src/opera/parser/tosca/v_1_3/capability_assignment.py
+++ b/src/opera/parser/tosca/v_1_3/capability_assignment.py
@@ -1,14 +1,12 @@
+from .range import Range
 from ..entity import Entity
 from ..map import Map
-from ..string import String
 from ..void import Void
 
-from .range import Range
-
 
 class CapabilityAssignment(Entity):
     ATTRS = dict(
         properties=Map(Void),
         attributes=Map(Void),
-        occurrences=Range,
+        occurrences=Range
     )
diff --git a/src/opera/parser/tosca/v_1_3/capability_definition.py b/src/opera/parser/tosca/v_1_3/capability_definition.py
index cd1ebeaa..f1e5b208 100644
--- a/src/opera/parser/tosca/v_1_3/capability_definition.py
+++ b/src/opera/parser/tosca/v_1_3/capability_definition.py
@@ -1,15 +1,12 @@
 from opera.parser.yaml.node import Node
-
-from ..entity import Entity
-from ..reference import Reference
-from ..map import Map
-from ..list import List
-from ..string import String
-from ..void import Void
-
 from .attribute_definition import AttributeDefinition
 from .property_definition import PropertyDefinition
 from .range import Range
+from ..entity import Entity
+from ..list import List
+from ..map import Map
+from ..reference import Reference
+from ..string import String
 
 
 class CapabilityDefinition(Entity):
diff --git a/src/opera/parser/tosca/v_1_3/capability_type.py b/src/opera/parser/tosca/v_1_3/capability_type.py
index 1ab21476..75b887d6 100644
--- a/src/opera/parser/tosca/v_1_3/capability_type.py
+++ b/src/opera/parser/tosca/v_1_3/capability_type.py
@@ -1,11 +1,9 @@
+from .attribute_definition import AttributeDefinition
+from .property_definition import PropertyDefinition
 from ..entity import TypeEntity
 from ..list import List
 from ..map import Map
 from ..reference import Reference
-from ..string import String
-
-from .attribute_definition import AttributeDefinition
-from .property_definition import PropertyDefinition
 
 
 class CapabilityType(TypeEntity):
diff --git a/src/opera/parser/tosca/v_1_3/collector_mixin.py b/src/opera/parser/tosca/v_1_3/collector_mixin.py
index c9661745..9ae6c620 100644
--- a/src/opera/parser/tosca/v_1_3/collector_mixin.py
+++ b/src/opera/parser/tosca/v_1_3/collector_mixin.py
@@ -1,6 +1,8 @@
+# type: ignore
+
+from opera.template.capability import Capability
 from opera.template.interface import Interface
 from opera.template.operation import Operation
-from opera.template.capability import Capability
 
 
 class CollectorMixin:
@@ -15,9 +17,7 @@ def collect_properties(self, service_ast):
 
         undeclared_props = set(assignments.keys()) - definitions.keys()
         if undeclared_props:
-            self.abort("Invalid properties: {}.".format(
-                ", ".join(undeclared_props),
-            ), self.loc)
+            self.abort("Invalid properties: {}.".format(", ".join(undeclared_props)), self.loc)
 
         for key, prop_definition in definitions.items():
             prop_required = prop_definition.get("required", None)
@@ -29,16 +29,15 @@ def collect_properties(self, service_ast):
                 prop_required = True
 
             if prop_required and not prop_has_default and not prop_assignment:
-                self.abort("Missing a required property: {}. If the property "
-                           "is optional please specify this in the definition "
-                           "with 'required: false' or supply its default "
-                           "value using 'default: <value>'.".format(key),
-                           self.loc)
+                self.abort(
+                    "Missing a required property: {}. If the property is optional please specify "
+                    "this in the definition with 'required: false' or supply its default value using "
+                    "'default: <value>'.".format(key), self.loc
+                )
 
         return {
-            name: (assignments.get(name) or definition).get_value(
-                definition.get_value_type(service_ast),
-            ) for name, definition in definitions.items()
+            name: (assignments.get(name) or definition).get_value(definition.get_value_type(service_ast))
+            for name, definition in definitions.items()
         }
 
     def collect_attributes(self, service_ast):
@@ -48,26 +47,21 @@ def collect_attributes(self, service_ast):
 
         undeclared_attrs = set(assignments.keys()) - definitions.keys()
         if undeclared_attrs:
-            self.abort("Invalid attributes: {}.".format(
-                ", ".join(undeclared_attrs),
-            ), self.loc)
-
+            self.abort("Invalid attributes: {}.".format(", ".join(undeclared_attrs)), self.loc)
         return {
             name: (assignments.get(name) or definition).get_value(
                 definition.get_value_type(service_ast),
             ) for name, definition in definitions.items()
         }
 
-    def collect_interfaces(self, service_ast):
+    def collect_interfaces(self, service_ast):  # pylint: disable=too-many-locals
         typ = self.type.resolve_reference(service_ast)
         definitions = typ.collect_interface_definitions(service_ast)
         assignments = self.get("interfaces", {})
 
         undeclared_interfaces = set(assignments.keys()) - definitions.keys()
         if undeclared_interfaces:
-            self.abort("Invalid interfaces: {}.".format(
-                ", ".join(undeclared_interfaces),
-            ), self.loc)
+            self.abort("Invalid interfaces: {}.".format(", ".join(undeclared_interfaces)), self.loc)
 
         # Next section is nasty. You have been warned.
         interfaces = {}
@@ -76,13 +70,9 @@ def collect_interfaces(self, service_ast):
 
             defined_operations = definition.get("operations", {})
             assigned_operations = assignment.get("operations", {})
-            undeclared_operations = (
-                    set(assigned_operations.keys()) - defined_operations.keys()
-            )
+            undeclared_operations = set(assigned_operations.keys()) - defined_operations.keys()
             if undeclared_operations:
-                self.abort("Undeclared operations: {}.".format(
-                    ", ".join(undeclared_operations),
-                ), self.loc)
+                self.abort("Undeclared operations: {}.".format(", ".join(undeclared_operations)), self.loc)
 
             operations = {}
             for op_name, op_definition in defined_operations.items():
@@ -132,10 +122,7 @@ def collect_interfaces(self, service_ast):
                 })
 
                 # Operation implementation details
-                impl = (
-                        op_assignment.get("implementation") or
-                        op_definition.get("implementation")
-                )
+                impl = op_assignment.get("implementation") or op_definition.get("implementation")
                 # TODO(@tadeboro): impl can be None here. Fix this.
                 timeout, operation_host = 0, None
                 if "timeout" in impl:
@@ -146,11 +133,8 @@ def collect_interfaces(self, service_ast):
                 operations[op_name] = Operation(
                     op_name,
                     primary=impl.primary.file.data,
-                    dependencies=[
-                        d.file.data for d in impl.get("dependencies", [])
-                    ],
-                    artifacts=[a.data for a in
-                               self.collect_artifacts(service_ast).values()],
+                    dependencies=[d.file.data for d in impl.get("dependencies", [])],
+                    artifacts=[a.data for a in self.collect_artifacts(service_ast).values()],
                     inputs=inputs,
                     outputs=outputs,
                     timeout=timeout,
@@ -168,14 +152,12 @@ def collect_capabilities(self, service_ast):
 
         undeclared_caps = set(assignments.keys()) - definitions.keys()
         if undeclared_caps:
-            self.abort("Invalid capabilities: {}.".format(
-                ", ".join(undeclared_caps),
-            ), self.loc)
-
-        return [Capability(name,
-                           assignment.get("properties", None),
-                           assignment.get("attributes", None))
-                for name, assignment in assignments.items()]
+            self.abort("Invalid capabilities: {}.".format(", ".join(undeclared_caps)), self.loc)
+
+        return [
+            Capability(name, assignment.get("properties", None), assignment.get("attributes", None))
+            for name, assignment in assignments.items()
+        ]
 
     def collect_artifacts(self, service_ast):
         typ = self.type.resolve_reference(service_ast)
diff --git a/src/opera/parser/tosca/v_1_3/condition_clause_definition.py b/src/opera/parser/tosca/v_1_3/condition_clause_definition.py
index a09c70a5..1b86bb0a 100644
--- a/src/opera/parser/tosca/v_1_3/condition_clause_definition.py
+++ b/src/opera/parser/tosca/v_1_3/condition_clause_definition.py
@@ -1,10 +1,15 @@
+from typing import Dict, Type, Union
+
 from .constraint_clause import ConstraintClause
+from ..base import Base
 from ..entity import Entity
 from ..list import List
+from ..map import Map
+from ..reference import Reference, ReferenceXOR
 
 
 class ConditionClauseDefinition(Entity):
-    ATTRS = dict()
+    ATTRS: Dict[str, Union[Type[Base], Base, Map, List, Reference, ReferenceXOR]] = dict()
     KEYNAMES = {"and", "or", "not"}
 
     @classmethod
diff --git a/src/opera/parser/tosca/v_1_3/data_type.py b/src/opera/parser/tosca/v_1_3/data_type.py
index 8626cbc2..0a19d799 100644
--- a/src/opera/parser/tosca/v_1_3/data_type.py
+++ b/src/opera/parser/tosca/v_1_3/data_type.py
@@ -1,13 +1,10 @@
 from opera.parser.yaml.node import Node
-
+from .constraint_clause import ConstraintClause
+from .property_definition import PropertyDefinition
 from ..entity import TypeEntity
 from ..list import List
 from ..map import Map
 from ..reference import DataTypeReference
-from ..string import String
-
-from .constraint_clause import ConstraintClause
-from .property_definition import PropertyDefinition
 
 
 class DataType(TypeEntity):
diff --git a/src/opera/parser/tosca/v_1_3/definition_collector_mixin.py b/src/opera/parser/tosca/v_1_3/definition_collector_mixin.py
index fdce67b3..cd96caa8 100644
--- a/src/opera/parser/tosca/v_1_3/definition_collector_mixin.py
+++ b/src/opera/parser/tosca/v_1_3/definition_collector_mixin.py
@@ -1,3 +1,5 @@
+# type: ignore
+
 import collections
 
 
@@ -6,7 +8,7 @@ def collect_types(self, service_ast):
         parent = self.derived_from.resolve_reference(service_ast)
         if not parent:
             return ()
-        return (self.derived_from.data, ) + parent.collect_types(service_ast)
+        return (self.derived_from.data,) + parent.collect_types(service_ast)
 
     def collect_property_definitions(self, service_ast):
         return self._collect_definitions("properties", service_ast)
@@ -24,7 +26,7 @@ def _collect_definitions(self, section, service_ast):
         defs = {}
         parent = self.derived_from.resolve_reference(service_ast)
         if parent:
-            defs.update(parent._collect_definitions(section, service_ast))
+            defs.update(parent._collect_definitions(section, service_ast))  # pylint: disable=protected-access
         defs.update(self.get(section, {}))
         return defs
 
diff --git a/src/opera/parser/tosca/v_1_3/group_type.py b/src/opera/parser/tosca/v_1_3/group_type.py
index bc2f05eb..8c7e3cc8 100644
--- a/src/opera/parser/tosca/v_1_3/group_type.py
+++ b/src/opera/parser/tosca/v_1_3/group_type.py
@@ -1,11 +1,9 @@
+from .attribute_definition import AttributeDefinition
+from .property_definition import PropertyDefinition
 from ..entity import TypeEntity
 from ..list import List
 from ..map import Map
 from ..reference import Reference
-from ..string import String
-
-from .attribute_definition import AttributeDefinition
-from .property_definition import PropertyDefinition
 
 
 class GroupType(TypeEntity):
diff --git a/src/opera/parser/tosca/v_1_3/import_definition.py b/src/opera/parser/tosca/v_1_3/import_definition.py
index 030210af..666ba701 100644
--- a/src/opera/parser/tosca/v_1_3/import_definition.py
+++ b/src/opera/parser/tosca/v_1_3/import_definition.py
@@ -1,9 +1,8 @@
+from opera.parser.tosca.entity import Entity
+from opera.parser.tosca.path import Path
+from opera.parser.tosca.string import String
 from opera.parser.yaml.node import Node
 
-from ..entity import Entity
-from ..path import Path
-from ..string import String
-
 
 class ImportDefinition(Entity):
     ATTRS = dict(
@@ -19,9 +18,7 @@ class ImportDefinition(Entity):
     @classmethod
     def normalize(cls, yaml_node):
         if not isinstance(yaml_node.value, (str, dict)):
-            cls.abort(
-                "Invalid import data. Expected string or dict.", yaml_node.loc,
-            )
+            cls.abort("Invalid import data. Expected string or dict.", yaml_node.loc)
         if isinstance(yaml_node.value, str):
             return Node({Node("file"): yaml_node})
         return yaml_node
diff --git a/src/opera/parser/tosca/v_1_3/interface_definition_for_template.py b/src/opera/parser/tosca/v_1_3/interface_definition_for_template.py
index 33b6dd07..04909878 100644
--- a/src/opera/parser/tosca/v_1_3/interface_definition_for_template.py
+++ b/src/opera/parser/tosca/v_1_3/interface_definition_for_template.py
@@ -1,11 +1,9 @@
+from .notification_definition import NotificationDefinition
+from .operation_definition_for_template import OperationDefinitionForTemplate
 from ..entity import Entity
 from ..map import Map
-from ..string import String
 from ..void import Void
 
-from .notification_definition import NotificationDefinition
-from .operation_definition_for_template import OperationDefinitionForTemplate
-
 
 class InterfaceDefinitionForTemplate(Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/interface_definition_for_type.py b/src/opera/parser/tosca/v_1_3/interface_definition_for_type.py
index eee3c65b..82f3f2b7 100644
--- a/src/opera/parser/tosca/v_1_3/interface_definition_for_type.py
+++ b/src/opera/parser/tosca/v_1_3/interface_definition_for_type.py
@@ -1,11 +1,9 @@
-from ..entity import Entity
-from ..map import Map
-from ..reference import Reference
-from ..string import String
-
 from .notification_definition import NotificationDefinition
 from .operation_definition_for_type import OperationDefinitionForType
 from .property_definition import PropertyDefinition
+from ..entity import Entity
+from ..map import Map
+from ..reference import Reference
 
 
 class InterfaceDefinitionForType(Entity):
diff --git a/src/opera/parser/tosca/v_1_3/interface_type.py b/src/opera/parser/tosca/v_1_3/interface_type.py
index 9e0fa168..d5ad21e9 100644
--- a/src/opera/parser/tosca/v_1_3/interface_type.py
+++ b/src/opera/parser/tosca/v_1_3/interface_type.py
@@ -1,11 +1,9 @@
-from ..entity import TypeEntity
-from ..map import Map
-from ..reference import Reference
-from ..string import String
-
 from .notification_definition import NotificationDefinition
 from .operation_definition_for_type import OperationDefinitionForType
 from .property_definition import PropertyDefinition
+from ..entity import TypeEntity
+from ..map import Map
+from ..reference import Reference
 
 
 class InterfaceType(TypeEntity):
diff --git a/src/opera/parser/tosca/v_1_3/node_template.py b/src/opera/parser/tosca/v_1_3/node_template.py
index 955dc2ac..f2d7040e 100644
--- a/src/opera/parser/tosca/v_1_3/node_template.py
+++ b/src/opera/parser/tosca/v_1_3/node_template.py
@@ -1,20 +1,18 @@
 from opera.template.node import Node
 from opera.template.requirement import Requirement
-
-from ..entity import Entity
-from ..list import List
-from ..map import Map
-from ..reference import Reference
-from ..string import String
-from ..void import Void
-
 from .artifact_definition import ArtifactDefinition
 from .capability_assignment import CapabilityAssignment
-from .collector_mixin import CollectorMixin
+from .collector_mixin import CollectorMixin  # type: ignore
 from .interface_definition_for_template import InterfaceDefinitionForTemplate
 from .node_filter_definition import NodeFilterDefinition
 from .relationship_template import RelationshipTemplate
 from .requirement_assignment import RequirementAssignment
+from ..entity import Entity
+from ..list import List
+from ..map import Map
+from ..reference import Reference
+from ..string import String
+from ..void import Void
 
 
 # NOTE: We deviate form the TOSCA standard in attribute assignment statement,
@@ -66,10 +64,7 @@ def collect_requirements(self, node_name, service_ast):
                 continue
 
             if not assignment.dig("node"):
-                self.abort(
-                    "Opera does not support abstract requirements",
-                    assignment.loc,
-                )
+                self.abort("Opera does not support abstract requirements", assignment.loc)
 
             # Validate node template reference
             assignment.node.resolve_reference(service_ast)
@@ -80,19 +75,15 @@ def collect_requirements(self, node_name, service_ast):
                 relationship_name = relationship_ref.data
             else:
                 # Create an anonymous relationship template of the right type
-                relationship = RelationshipTemplate(
-                    dict(type=definitions[name].relationship), None,
-                )
-                relationship_name = "{}-{}-{}".format(
-                    node_name, name, assignment.node.data,
-                )
+                relationship = RelationshipTemplate(dict(type=definitions[name].relationship), None)
+                relationship_name = "{}-{}-{}".format(node_name, name, assignment.node.data)
 
             occurrences = definitions[name].get("occurrences")
 
-            requirements.append(Requirement(
-                name, assignment.node.data,
-                relationship.get_template(relationship_name, service_ast),
-                occurrences,
-            ))
+            requirements.append(
+                Requirement(
+                    name, assignment.node.data, relationship.get_template(relationship_name, service_ast), occurrences
+                )
+            )
 
         return requirements
diff --git a/src/opera/parser/tosca/v_1_3/node_type.py b/src/opera/parser/tosca/v_1_3/node_type.py
index 2b0813a1..a8831a95 100644
--- a/src/opera/parser/tosca/v_1_3/node_type.py
+++ b/src/opera/parser/tosca/v_1_3/node_type.py
@@ -1,15 +1,13 @@
-from ..entity import TypeEntity
-from ..map import Map, OrderedMap
-from ..reference import Reference
-from ..string import String
-
 from .artifact_definition import ArtifactDefinition
 from .attribute_definition import AttributeDefinition
 from .capability_definition import CapabilityDefinition
-from .definition_collector_mixin import DefinitionCollectorMixin
+from .definition_collector_mixin import DefinitionCollectorMixin  # type: ignore
 from .interface_definition_for_type import InterfaceDefinitionForType
 from .property_definition import PropertyDefinition
 from .requirement_definition import RequirementDefinition
+from ..entity import TypeEntity
+from ..map import Map, OrderedMap
+from ..reference import Reference
 
 
 class NodeType(DefinitionCollectorMixin, TypeEntity):
diff --git a/src/opera/parser/tosca/v_1_3/notification_definition.py b/src/opera/parser/tosca/v_1_3/notification_definition.py
index 567478e3..a36f5029 100644
--- a/src/opera/parser/tosca/v_1_3/notification_definition.py
+++ b/src/opera/parser/tosca/v_1_3/notification_definition.py
@@ -1,13 +1,12 @@
+from .notification_implementation_definition import (
+    NotificationImplementationDefinition,
+)
 from ..entity import Entity
-from ..string import String
 from ..list import List
 from ..map import Map
+from ..string import String
 from ..void import Void
 
-from .notification_implementation_definition import (
-    NotificationImplementationDefinition,
-)
-
 
 class NotificationDefinition(Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/notification_implementation_definition.py b/src/opera/parser/tosca/v_1_3/notification_implementation_definition.py
index 5d515dd9..09425168 100644
--- a/src/opera/parser/tosca/v_1_3/notification_implementation_definition.py
+++ b/src/opera/parser/tosca/v_1_3/notification_implementation_definition.py
@@ -1,10 +1,8 @@
 from opera.parser.yaml.node import Node
-
+from .artifact_definition import ArtifactDefinition
 from ..entity import Entity
 from ..list import List
 
-from .artifact_definition import ArtifactDefinition
-
 
 class NotificationImplementationDefinition(Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/operation_definition_for_template.py b/src/opera/parser/tosca/v_1_3/operation_definition_for_template.py
index 07846a88..a517cb9e 100644
--- a/src/opera/parser/tosca/v_1_3/operation_definition_for_template.py
+++ b/src/opera/parser/tosca/v_1_3/operation_definition_for_template.py
@@ -1,15 +1,13 @@
 from opera.parser.yaml.node import Node
-
+from .operation_implementation_definition import (
+    OperationImplementationDefinition,
+)
 from ..entity import Entity
 from ..list import List
 from ..map import Map
 from ..string import String
 from ..void import Void
 
-from .operation_implementation_definition import (
-    OperationImplementationDefinition,
-)
-
 
 class OperationDefinitionForTemplate(Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/operation_definition_for_type.py b/src/opera/parser/tosca/v_1_3/operation_definition_for_type.py
index 50f91ad4..f7cd47d9 100644
--- a/src/opera/parser/tosca/v_1_3/operation_definition_for_type.py
+++ b/src/opera/parser/tosca/v_1_3/operation_definition_for_type.py
@@ -1,14 +1,12 @@
 from opera.parser.yaml.node import Node
-
-from ..entity import Entity
-from ..list import List
-from ..map import Map
-from ..string import String
-
 from .operation_implementation_definition import (
     OperationImplementationDefinition,
 )
 from .property_definition import PropertyDefinition
+from ..entity import Entity
+from ..list import List
+from ..map import Map
+from ..string import String
 
 
 class OperationDefinitionForType(Entity):
diff --git a/src/opera/parser/tosca/v_1_3/operation_host.py b/src/opera/parser/tosca/v_1_3/operation_host.py
index d080c4e9..9cfd1a98 100644
--- a/src/opera/parser/tosca/v_1_3/operation_host.py
+++ b/src/opera/parser/tosca/v_1_3/operation_host.py
@@ -8,8 +8,5 @@ class OperationHost(String):
     def validate(cls, yaml_node):
         super().validate(yaml_node)
         if yaml_node.value not in cls.VALID_HOSTS:
-            cls.abort(
-                "Invalid operation host: {}. Use any from: {}".format(
-                    yaml_node.value, ", ".join(cls.VALID_HOSTS),
-                ), yaml_node.loc,
-            )
+            cls.abort("Invalid operation host: {}. Use any from: {}"
+                      .format(yaml_node.value, ", ".join(cls.VALID_HOSTS)), yaml_node.loc)
diff --git a/src/opera/parser/tosca/v_1_3/operation_implementation_definition.py b/src/opera/parser/tosca/v_1_3/operation_implementation_definition.py
index a774bb99..2a07d2e7 100644
--- a/src/opera/parser/tosca/v_1_3/operation_implementation_definition.py
+++ b/src/opera/parser/tosca/v_1_3/operation_implementation_definition.py
@@ -1,12 +1,10 @@
 from opera.parser.yaml.node import Node
-
+from .artifact_definition import ArtifactDefinition
+from .operation_host import OperationHost
 from ..entity import Entity
 from ..integer import Integer
 from ..list import List
 
-from .artifact_definition import ArtifactDefinition
-from .operation_host import OperationHost
-
 
 class OperationImplementationDefinition(Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/parameter_definition.py b/src/opera/parser/tosca/v_1_3/parameter_definition.py
index a083909a..9ff9f110 100644
--- a/src/opera/parser/tosca/v_1_3/parameter_definition.py
+++ b/src/opera/parser/tosca/v_1_3/parameter_definition.py
@@ -1,5 +1,7 @@
 from opera.value import Value
-
+from .constraint_clause import ConstraintClause
+from .schema_definition import SchemaDefinition
+from .status import Status
 from ..bool import Bool
 from ..entity import Entity
 from ..list import List
@@ -9,11 +11,6 @@
 from ..void import Void
 
 
-from .constraint_clause import ConstraintClause
-from .schema_definition import SchemaDefinition
-from .status import Status
-
-
 # TODO(@tadeboro): Unify ParameterDefinition and PropertyDefinition and add
 # runtime checks. Refinement will be a PITA ...
 
@@ -40,6 +37,6 @@ def get_value(self, typ):
             return self.default.get_value(typ)
         return Value(typ, False)
 
-    def get_value_type(self, service_ast):
+    def get_value_type(self, service_ast):  # pylint: disable=no-self-use
         # TODO(@tadeboro): Implement type checks.
         return None
diff --git a/src/opera/parser/tosca/v_1_3/policy_definition.py b/src/opera/parser/tosca/v_1_3/policy_definition.py
index 011f4fbc..4b0568d6 100644
--- a/src/opera/parser/tosca/v_1_3/policy_definition.py
+++ b/src/opera/parser/tosca/v_1_3/policy_definition.py
@@ -1,3 +1,4 @@
+from .trigger_definition import TriggerDefinition
 from ..entity import Entity
 from ..list import List
 from ..map import Map
@@ -5,8 +6,6 @@
 from ..string import String
 from ..void import Void
 
-from .trigger_definition import TriggerDefinition
-
 
 class PolicyDefinition(Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/policy_type.py b/src/opera/parser/tosca/v_1_3/policy_type.py
index dc53d120..b66570df 100644
--- a/src/opera/parser/tosca/v_1_3/policy_type.py
+++ b/src/opera/parser/tosca/v_1_3/policy_type.py
@@ -1,11 +1,10 @@
+from .property_definition import PropertyDefinition
+from .trigger_definition import TriggerDefinition
 from ..entity import TypeEntity
 from ..list import List
 from ..map import Map
 from ..reference import Reference, ReferenceXOR
 
-from .property_definition import PropertyDefinition
-from .trigger_definition import TriggerDefinition
-
 
 class PolicyType(TypeEntity):
     REFERENCE = Reference("policy_types")
diff --git a/src/opera/parser/tosca/v_1_3/property_definition.py b/src/opera/parser/tosca/v_1_3/property_definition.py
index f8cca319..f245bd08 100644
--- a/src/opera/parser/tosca/v_1_3/property_definition.py
+++ b/src/opera/parser/tosca/v_1_3/property_definition.py
@@ -1,5 +1,7 @@
 from opera.value import Value
-
+from .constraint_clause import ConstraintClause
+from .schema_definition import SchemaDefinition
+from .status import Status
 from ..bool import Bool
 from ..entity import Entity
 from ..list import List
@@ -8,10 +10,6 @@
 from ..string import String
 from ..void import Void
 
-from .constraint_clause import ConstraintClause
-from .schema_definition import SchemaDefinition
-from .status import Status
-
 
 class PropertyDefinition(Entity):
     ATTRS = dict(
@@ -35,6 +33,6 @@ def get_value(self, typ):
             return self.default.get_value(typ)
         return Value(typ, False)
 
-    def get_value_type(self, service_ast):
+    def get_value_type(self, service_ast):  # pylint: disable=no-self-use
         # TODO(@tadeboro): Implement types later.
         return None
diff --git a/src/opera/parser/tosca/v_1_3/range.py b/src/opera/parser/tosca/v_1_3/range.py
index 1824f22b..ef5f1dad 100644
--- a/src/opera/parser/tosca/v_1_3/range.py
+++ b/src/opera/parser/tosca/v_1_3/range.py
@@ -28,15 +28,9 @@ def validate(cls, yaml_node):
             cls.abort("Upper bound must be integer or UNBOUNDED.", hi.loc)
 
         if isinstance(hi.value, int) and lo.value > hi.value:
-            cls.abort(
-                "Upper bound must be greater or equal to lower bound.",
-                yaml_node.loc,
-            )
+            cls.abort("Upper bound must be greater or equal to lower bound.", yaml_node.loc)
 
     @classmethod
     def build(cls, yaml_node):
         lo, hi = yaml_node.value
-        return cls(
-            (lo.value, math.inf if hi.value == "UNBOUNDED" else hi.value),
-            yaml_node.loc,
-        )
+        return cls((lo.value, math.inf if hi.value == "UNBOUNDED" else hi.value), yaml_node.loc)
diff --git a/src/opera/parser/tosca/v_1_3/relationship_template.py b/src/opera/parser/tosca/v_1_3/relationship_template.py
index c5f5065c..aed4597c 100644
--- a/src/opera/parser/tosca/v_1_3/relationship_template.py
+++ b/src/opera/parser/tosca/v_1_3/relationship_template.py
@@ -1,17 +1,12 @@
-import collections
-
 from opera.template.relationship import Relationship
-from opera.template.operation import Operation
-
+from .collector_mixin import CollectorMixin  # type: ignore
+from .interface_definition_for_template import InterfaceDefinitionForTemplate
 from ..entity import Entity
 from ..map import Map
 from ..reference import Reference
 from ..string import String
 from ..void import Void
 
-from .collector_mixin import CollectorMixin
-from .interface_definition_for_template import InterfaceDefinitionForTemplate
-
 
 class RelationshipTemplate(CollectorMixin, Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/relationship_type.py b/src/opera/parser/tosca/v_1_3/relationship_type.py
index 02917464..50518b47 100644
--- a/src/opera/parser/tosca/v_1_3/relationship_type.py
+++ b/src/opera/parser/tosca/v_1_3/relationship_type.py
@@ -1,13 +1,11 @@
+from .attribute_definition import AttributeDefinition
+from .definition_collector_mixin import DefinitionCollectorMixin  # type: ignore
+from .interface_definition_for_type import InterfaceDefinitionForType
+from .property_definition import PropertyDefinition
 from ..entity import TypeEntity
 from ..list import List
 from ..map import Map
 from ..reference import Reference
-from ..string import String
-
-from .attribute_definition import AttributeDefinition
-from .definition_collector_mixin import DefinitionCollectorMixin
-from .interface_definition_for_type import InterfaceDefinitionForType
-from .property_definition import PropertyDefinition
 
 
 class RelationshipType(DefinitionCollectorMixin, TypeEntity):
diff --git a/src/opera/parser/tosca/v_1_3/repository_definition.py b/src/opera/parser/tosca/v_1_3/repository_definition.py
index 9148aff4..c119cdfa 100644
--- a/src/opera/parser/tosca/v_1_3/repository_definition.py
+++ b/src/opera/parser/tosca/v_1_3/repository_definition.py
@@ -1,10 +1,8 @@
 from opera.parser.yaml.node import Node
-
+from .credential import Credential
 from ..entity import Entity
 from ..string import String
 
-from .credential import Credential
-
 
 class RepositoryDefinition(Entity):
     ATTRS = dict(
@@ -17,10 +15,7 @@ class RepositoryDefinition(Entity):
     @classmethod
     def normalize(cls, yaml_node):
         if not isinstance(yaml_node.value, (str, dict)):
-            cls.abort(
-                "Invalid repository data. Expected string or dict.",
-                yaml_node.loc,
-            )
+            cls.abort("Invalid repository data. Expected string or dict.", yaml_node.loc)
         if isinstance(yaml_node.value, str):
             return Node({Node("url"): yaml_node})
         return yaml_node
diff --git a/src/opera/parser/tosca/v_1_3/requirement_assignment.py b/src/opera/parser/tosca/v_1_3/requirement_assignment.py
index 7da3ba00..6ad4e0c4 100644
--- a/src/opera/parser/tosca/v_1_3/requirement_assignment.py
+++ b/src/opera/parser/tosca/v_1_3/requirement_assignment.py
@@ -1,12 +1,9 @@
 from opera.parser.yaml.node import Node
-
+from .node_filter_definition import NodeFilterDefinition
+from .range import Range
 from ..entity import Entity
 from ..reference import Reference
 from ..string import String
-from ..void import Void
-
-from .node_filter_definition import NodeFilterDefinition
-from .range import Range
 
 
 class RequirementAssignment(Entity):
diff --git a/src/opera/parser/tosca/v_1_3/requirement_definition.py b/src/opera/parser/tosca/v_1_3/requirement_definition.py
index 155fc1f5..caeb749b 100644
--- a/src/opera/parser/tosca/v_1_3/requirement_definition.py
+++ b/src/opera/parser/tosca/v_1_3/requirement_definition.py
@@ -1,10 +1,8 @@
 from opera.parser.yaml.node import Node
-
+from .range import Range
 from ..entity import Entity
 from ..reference import Reference
 
-from .range import Range
-
 
 class RequirementDefinition(Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/schema_definition.py b/src/opera/parser/tosca/v_1_3/schema_definition.py
index 90f7f2d4..3506bb06 100644
--- a/src/opera/parser/tosca/v_1_3/schema_definition.py
+++ b/src/opera/parser/tosca/v_1_3/schema_definition.py
@@ -1,10 +1,9 @@
+from .constraint_clause import ConstraintClause
 from ..entity import Entity
 from ..list import List
 from ..reference import DataTypeReference
 from ..string import String
 
-from .constraint_clause import ConstraintClause
-
 
 class SchemaDefinition(Entity):
     ATTRS = dict(
diff --git a/src/opera/parser/tosca/v_1_3/service_template.py b/src/opera/parser/tosca/v_1_3/service_template.py
index 13288b71..145a106b 100644
--- a/src/opera/parser/tosca/v_1_3/service_template.py
+++ b/src/opera/parser/tosca/v_1_3/service_template.py
@@ -1,13 +1,5 @@
-import pathlib
-
 from opera.parser import yaml
 from opera.parser.yaml.node import Node
-
-from ..entity import Entity
-from ..list import List
-from ..map import Map
-from ..string import String
-
 from .artifact_type import ArtifactType
 from .capability_type import CapabilityType
 from .data_type import DataType
@@ -20,6 +12,10 @@
 from .repository_definition import RepositoryDefinition
 from .topology_template import TopologyTemplate
 from .tosca_definitions_version import ToscaDefinitionsVersion
+from ..entity import Entity
+from ..list import List
+from ..map import Map
+from ..string import String
 
 
 class ServiceTemplate(Entity):
@@ -49,19 +45,13 @@ def normalize(cls, yaml_node):
             cls.abort("TOSCA document should be a map.", yaml_node.loc)
 
         # Filter out dsl_definitions, since they are preprocessor construct.
-        return Node({
-            k: v
-            for k, v in yaml_node.value.items()
-            if k.value != "dsl_definitions"
-        }, yaml_node.loc)
+        return Node({k: v for k, v in yaml_node.value.items() if k.value != "dsl_definitions"}, yaml_node.loc)
 
     @classmethod
-    def parse(cls, yaml_node, base_path, template_path, parsed_templates):
-        service = super().parse(yaml_node)
+    def parse_service_template(cls, yaml_node, base_path, template_path, parsed_templates):
+        service = cls.parse(yaml_node)
         service.visit("prefix_path", template_path.parent)
-        parsed = service.merge_imports(
-            base_path, parsed_templates | set([template_path]),
-        )
+        parsed = service.merge_imports(base_path, parsed_templates | {template_path})
         return service, parsed
 
     def merge_imports(self, base_path, parsed_templates):
@@ -76,9 +66,7 @@ def merge_imports(self, base_path, parsed_templates):
 
             with (base_path / import_path).open() as fd:
                 yaml_data = yaml.load(fd, str(import_path))
-            ast, parsed = ServiceTemplate.parse(
-                yaml_data, base_path, import_path, parsed,
-            )
+            ast, parsed = ServiceTemplate.parse_service_template(yaml_data, base_path, import_path, parsed)
             self.merge(ast)
 
         # We do not need imports anymore, since they are preprocessor
@@ -89,12 +77,9 @@ def merge_imports(self, base_path, parsed_templates):
 
     def merge(self, other):
         if self.tosca_definitions_version != other.tosca_definitions_version:
-            self.abort(
-                "Incompatible TOSCA definitions: {} and {}".format(
-                    self.tosca_definitions_version,
-                    other.tosca_definitions_version
-                ), other.loc,
-            )
+            self.abort("Incompatible TOSCA definitions: {} and {}".format(
+                self.tosca_definitions_version, other.tosca_definitions_version
+            ), other.loc)
 
         # TODO(@tadeboro): Should we merge the topology templates or should we
         # be doing substitution mapping instead?
@@ -108,7 +93,7 @@ def merge(self, other):
                 "node_types",
                 "group_types",
                 "policy_types",
-                "topology_template",
+                "topology_template"
         ):
             if key not in other.data:
                 continue
diff --git a/src/opera/parser/tosca/v_1_3/status.py b/src/opera/parser/tosca/v_1_3/status.py
index 8f3a75fb..c908aac8 100644
--- a/src/opera/parser/tosca/v_1_3/status.py
+++ b/src/opera/parser/tosca/v_1_3/status.py
@@ -8,6 +8,4 @@ class Status(String):
     def validate(cls, yaml_node):
         super().validate(yaml_node)
         if yaml_node.value not in cls.VALID_STATES:
-            cls.abort(
-                "Invalid state: '{}'.".format(yaml_node.value), yaml_node.loc,
-            )
+            cls.abort("Invalid state: '{}'.".format(yaml_node.value), yaml_node.loc)
diff --git a/src/opera/parser/tosca/v_1_3/topology_template.py b/src/opera/parser/tosca/v_1_3/topology_template.py
index 495bfbf1..70e471ea 100644
--- a/src/opera/parser/tosca/v_1_3/topology_template.py
+++ b/src/opera/parser/tosca/v_1_3/topology_template.py
@@ -1,16 +1,14 @@
 from opera.error import DataError
 from opera.template.topology import Topology
-
-from ..entity import Entity
-from ..map import Map
-from ..list import List
-from ..string import String
-
 from .group_definition import GroupDefinition
 from .node_template import NodeTemplate
 from .parameter_definition import ParameterDefinition
 from .policy_definition import PolicyDefinition
 from .relationship_template import RelationshipTemplate
+from ..entity import Entity
+from ..list import List
+from ..map import Map
+from ..string import String
 
 
 class TopologyTemplate(Entity):
@@ -35,8 +33,7 @@ def get_template(self, inputs, service_ast):
             },
             relationships={
                 name: rel_ast.get_template(name, service_ast)
-                for name, rel_ast in
-                self.get("relationship_templates", {}).items()
+                for name, rel_ast in self.get("relationship_templates", {}).items()
             },
         )
         topology.resolve_requirements()
@@ -47,9 +44,7 @@ def collect_inputs(self, inputs, service_ast):
         undeclared_inputs = set(inputs.keys()) - declared_inputs.keys()
 
         if undeclared_inputs:
-            raise DataError("Undeclared inputs: {}".format(
-                ", ".join(undeclared_inputs),
-            ))
+            raise DataError("Undeclared inputs: {}".format(", ".join(undeclared_inputs)))
 
         input_values = {
             name: definition.get_value(definition.get_value_type(service_ast))
@@ -65,9 +60,7 @@ def collect_outputs(self, service_ast):
         return {
             name: dict(
                 description=getattr(definition.get("description"), "data", ""),
-                value=definition.get_value(
-                    definition.get_value_type(service_ast),
-                ),
+                value=definition.get_value(definition.get_value_type(service_ast)),
             ) for name, definition in self.get("outputs", {}).items()
         }
 
diff --git a/src/opera/parser/tosca/v_1_3/tosca_definitions_version.py b/src/opera/parser/tosca/v_1_3/tosca_definitions_version.py
index 1ad779b7..608d183b 100644
--- a/src/opera/parser/tosca/v_1_3/tosca_definitions_version.py
+++ b/src/opera/parser/tosca/v_1_3/tosca_definitions_version.py
@@ -7,9 +7,8 @@ def validate(cls, yaml_node):
         super().validate(yaml_node)
         if yaml_node.value != "tosca_simple_yaml_1_3":
             cls.abort(
-                "Invalid TOSCA version: {}. Expected {}.".format(
-                    yaml_node.value, "tosca_simple_yaml_1_3",
-                ), yaml_node.loc,
+                "Invalid TOSCA version: {}. Expected {}.".format(yaml_node.value, "tosca_simple_yaml_1_3"),
+                yaml_node.loc
             )
 
     def eval(self, _reference):
diff --git a/src/opera/parser/tosca/v_1_3/trigger_definition.py b/src/opera/parser/tosca/v_1_3/trigger_definition.py
index 9f0c9fa9..a0de8096 100644
--- a/src/opera/parser/tosca/v_1_3/trigger_definition.py
+++ b/src/opera/parser/tosca/v_1_3/trigger_definition.py
@@ -1,16 +1,13 @@
-from opera.value import Value
-
+from .activity_definition import ActivityDefinition
+from .condition_clause_definition import ConditionClauseDefinition
+from .event_filter_definition import EventFilterDefinition
+from .time_interval import TimeInterval
 from ..entity import Entity
-from ..string import String
 from ..integer import Integer
-from ..void import Void
 from ..list import List
+from ..string import String
 from ..type import Type
-
-from .time_interval import TimeInterval
-from .event_filter_definition import EventFilterDefinition
-from .activity_definition import ActivityDefinition
-from .condition_clause_definition import ConditionClauseDefinition
+from ..void import Void
 
 
 class TriggerDefinition(Entity):
diff --git a/src/opera/parser/tosca/version.py b/src/opera/parser/tosca/version.py
index 7777170a..1c540e66 100644
--- a/src/opera/parser/tosca/version.py
+++ b/src/opera/parser/tosca/version.py
@@ -2,7 +2,6 @@
 
 from .string import String
 
-
 # TOSCA definition: <major>.<minor>[.<fix>[.<qualifier>[-<build]]]
 #   major: is a required integer value greater than or equal to 0 (zero)
 #   minor: is a required integer value greater than or equal to 0 (zero).
diff --git a/src/opera/parser/tosca/void.py b/src/opera/parser/tosca/void.py
index 49f86727..85598242 100644
--- a/src/opera/parser/tosca/void.py
+++ b/src/opera/parser/tosca/void.py
@@ -1,14 +1,9 @@
+from opera.parser.tosca.base import Base
 from opera.value import Value
-from opera.parser.yaml.node import Node
-
-from .base import Base
 
 
 class Void(Base):
-    """
-    Marker for parts of the document that should be parsed after initial
-    semantic analysis.
-    """
+    """Marker for parts of the document that should be parsed after initial semantic analysis."""
 
     @classmethod
     def build(cls, yaml_node):
diff --git a/src/opera/parser/yaml/__init__.py b/src/opera/parser/yaml/__init__.py
index 3b3b8176..7a9eaac6 100644
--- a/src/opera/parser/yaml/__init__.py
+++ b/src/opera/parser/yaml/__init__.py
@@ -2,8 +2,8 @@
 
 
 def load(stream, stream_path):
-    loader = Loader(stream, stream_path)
+    ldr = Loader(stream, stream_path)
     try:
-        return loader.get_single_data()
+        return ldr.get_single_data()
     finally:
-        loader.dispose()
+        ldr.dispose()
diff --git a/src/opera/parser/yaml/constructor.py b/src/opera/parser/yaml/constructor.py
index 154526a5..c9678722 100644
--- a/src/opera/parser/yaml/constructor.py
+++ b/src/opera/parser/yaml/constructor.py
@@ -1,8 +1,8 @@
-from yaml.constructor import BaseConstructor, ConstructorError
 from collections import Counter
 
-from opera.parser.utils.location import Location
+from yaml.constructor import BaseConstructor, ConstructorError
 
+from opera.parser.utils.location import Location
 from .node import Node
 
 
@@ -62,11 +62,12 @@ def construct_yaml_map(self, node):
         if duplicates:
             raise ConstructorError(
                 None, None,
-                "Duplicate map names: {}".format(', '.join(duplicates)),
+                "Duplicate map names: {}".format(", ".join(duplicates)),
                 node.start_mark,
             )
 
-    def construct_undefined(self, node):
+    @staticmethod
+    def construct_undefined(node):
         raise ConstructorError(
             None, None,
             "could not determine a constructor for {}".format(node.tag),
diff --git a/src/opera/parser/yaml/loader.py b/src/opera/parser/yaml/loader.py
index 1a6a56f8..d48eda31 100644
--- a/src/opera/parser/yaml/loader.py
+++ b/src/opera/parser/yaml/loader.py
@@ -1,11 +1,11 @@
 from .constructor import Constructor
 from .resolver import Resolver
 
-
 try:
     from _yaml import CParser
 
-    class Loader(CParser, Constructor, Resolver):
+
+    class Loader(CParser, Constructor, Resolver):  # noqa: E303
         def __init__(self, stream, stream_name):
             CParser.__init__(self, stream)
             Constructor.__init__(self, stream_name)
@@ -18,7 +18,9 @@ def __init__(self, stream, stream_name):
     from yaml.reader import Reader
     from yaml.scanner import Scanner
 
-    class Loader(Reader, Scanner, Parser, Composer, Constructor, Resolver):
+
+    class Loader(Reader, Scanner, Parser,  # type: ignore # noqa: E303, E501; # pylint: disable=too-many-ancestors
+                 Composer, Constructor, Resolver):
         def __init__(self, stream, stream_name):
             Reader.__init__(self, stream)
             Scanner.__init__(self)
diff --git a/src/opera/parser/yaml/node.py b/src/opera/parser/yaml/node.py
index 1a0b5799..7c5d65cf 100644
--- a/src/opera/parser/yaml/node.py
+++ b/src/opera/parser/yaml/node.py
@@ -8,9 +8,9 @@ def __init__(self, value, loc=None):
 
     @property
     def bare(self):
-        if type(self.value) is list:
+        if isinstance(self.value, list):
             return [v.bare for v in self.value]
-        if type(self.value) is dict:
+        if isinstance(self.value, dict):
             return {k.bare: v.bare for k, v in self.value.items()}
         return self.value
 
diff --git a/src/opera/parser/yaml/resolver.py b/src/opera/parser/yaml/resolver.py
index 738951f2..7fa29617 100644
--- a/src/opera/parser/yaml/resolver.py
+++ b/src/opera/parser/yaml/resolver.py
@@ -1,4 +1,5 @@
 import re
+from typing import Dict, List, Tuple, Pattern
 
 from yaml.nodes import MappingNode, ScalarNode, SequenceNode
 
@@ -9,12 +10,12 @@ class Resolver:
         SequenceNode: "tag:yaml.org,2002:seq",
         MappingNode: "tag:yaml.org,2002:map",
     }
-    resolvers = {}
+    resolvers: Dict[str, List[Tuple[str, Pattern]]] = {}
 
     @classmethod
     def add_implicit_resolver(cls, tag, regex, first):
-        for ch in first:
-            cls.resolvers.setdefault(ch, []).append((tag, regex))
+        for character in first:
+            cls.resolvers.setdefault(character, []).append((tag, regex))
 
     def resolve(self, kind, value, implicit):
         if kind is ScalarNode and implicit[0]:
@@ -24,10 +25,10 @@ def resolve(self, kind, value, implicit):
                     return tag
         return self.defaults[kind]
 
-    def descend_resolver(_self, _current_node, _current_index):
+    def descend_resolver(self, _current_node, _current_index):
         pass
 
-    def ascend_resolver(_self):
+    def ascend_resolver(self):
         pass
 
 
diff --git a/src/opera/stdlib/v_1_3.yaml b/src/opera/stdlib/v_1_3.yaml
index 771d29d3..57900c10 100644
--- a/src/opera/stdlib/v_1_3.yaml
+++ b/src/opera/stdlib/v_1_3.yaml
@@ -300,7 +300,7 @@ data_types:
         type: tosca.datatypes.network.PortDef
         required: false
 
-  
+
 group_types:
   tosca.groups.Root:
     derived_from: tosca.entity.Root
diff --git a/src/opera/storage.py b/src/opera/storage.py
index 4eae101b..050de195 100644
--- a/src/opera/storage.py
+++ b/src/opera/storage.py
@@ -41,4 +41,3 @@ def remove_all(self):
         shutil.rmtree(self.path)
         # the storage dir needs to exist after we delete the content
         pathlib.Path(self.path).mkdir(exist_ok=True)
-
diff --git a/src/opera/template/capability.py b/src/opera/template/capability.py
index 11298d3f..ed68e154 100644
--- a/src/opera/template/capability.py
+++ b/src/opera/template/capability.py
@@ -1,5 +1,5 @@
 class Capability:
     def __init__(self, name, properties, attributes):
         self.name = name
-        self.properties = properties,
+        self.properties = properties
         self.attributes = attributes
diff --git a/src/opera/template/node.py b/src/opera/template/node.py
index e8966070..b223a354 100644
--- a/src/opera/template/node.py
+++ b/src/opera/template/node.py
@@ -1,8 +1,10 @@
 from collections import Counter
+from pathlib import Path
+from typing import Dict
 
 from opera.error import DataError
 from opera.instance.node import Node as Instance
-from pathlib import Path
+from opera.template.topology import Topology
 
 
 class Node:
@@ -27,10 +29,10 @@ def __init__(
         self.artifacts = artifacts
 
         # This will be set when the node is inserted into a topology
-        self.topology = None
+        self.topology: Topology = None
 
         # This will be set at instantiation time.
-        self.instances = None
+        self.instances: Dict = None  # type: ignore
 
     def resolve_requirements(self, topology):
         requirement_occurrences = Counter([r.name for r in self.requirements])
@@ -40,17 +42,11 @@ def resolve_requirements(self, topology):
             max_occurrences = occurrences_range[1] if occurrences_range else 1
 
             if requirement_occurrences[r.name] < min_occurrences:
-                raise DataError(
-                    "Not enough occurrences found for requirement '{}'. "
-                    "Minimum is: {}".format(
-                        r.name, min_occurrences
-                    ))
+                raise DataError("Not enough occurrences found for requirement '{}'. Minimum is: {}"
+                                .format(r.name, min_occurrences))
             if requirement_occurrences[r.name] > max_occurrences:
-                raise DataError(
-                    "Too many occurrences found for requirement '{}'. "
-                    "Maximum is: {}".format(
-                        r.name, max_occurrences
-                    ))
+                raise DataError("Too many occurrences found for requirement '{}'. Maximum is: {}"
+                                .format(r.name, max_occurrences))
             r.resolve(topology)
 
     def is_a(self, typ):
@@ -75,8 +71,7 @@ def get_host(self):
         host = next((
             r.target
             for r in self.requirements
-            if r.relationship.is_a("tosca.relationships.HostedOn")
-               and r.target.is_a("tosca.nodes.Compute")
+            if r.relationship.is_a("tosca.relationships.HostedOn") and r.target.is_a("tosca.nodes.Compute")
         ), None)
         if host:
             instance = next(iter(host.instances.values()))
@@ -109,9 +104,8 @@ def get_property(self, params):
             raise DataError("HOST is not yet supported in opera.")
         if host != "SELF":
             raise DataError(
-                "Property host should be set to 'SELF' which is the only "
-                "valid value. This is needed to indicate that the property is "
-                "referenced locally from something in the node itself."
+                "Property host should be set to 'SELF' which is the only valid value. This is needed to indicate that "
+                "the property is referenced locally from something in the node itself."
             )
 
         # TODO(@tadeboro): Add support for nested property values.
@@ -119,45 +113,35 @@ def get_property(self, params):
             return self.properties[prop].eval(self, prop)
 
         # Check if there are capability and requirement with the same name.
-        if prop in [r.name for r in self.requirements] and prop \
-                in [c.name for c in self.capabilities]:
-            raise DataError("There are capability and requirement with the "
-                            "same name: '{}'.".format(prop, ))
+        if prop in [r.name for r in self.requirements] \
+                and prop in [c.name for c in self.capabilities]:
+            raise DataError("There are capability and requirement with the same name: '{}'.".format(prop, ))
 
         # If we have no property, try searching for capability.
-        capabilities = tuple(
-            c for c in self.capabilities if c.name == prop
-        )
+        capabilities = tuple(c for c in self.capabilities if c.name == prop)
         if len(capabilities) > 1:
-            raise DataError("More than one capability is named '{}'.".format(
-                prop,
-            ))
+            raise DataError("More than one capability is named '{}'.".format(prop))
 
         if len(capabilities) == 1 and capabilities[0].properties:
-            return capabilities[0].properties[0].get(rest[0]).data
+            return capabilities[0].properties.get(rest[0]).data
 
         # If we have no property, try searching for requirement.
-        requirements = tuple(
-            r for r in self.requirements if r.name == prop
-        )
+        requirements = tuple(r for r in self.requirements if r.name == prop)
         if len(requirements) == 0:
             raise DataError("Cannot find property '{}'.".format(prop))
         if len(requirements) > 1:
-            raise DataError("More than one requirement is named '{}'.".format(
-                prop,
-            ))
+            raise DataError("More than one requirement is named '{}'.".format(prop))
         return requirements[0].target.get_property(["SELF"] + rest)
 
     def get_attribute(self, params):
-        host, attr, *rest = params
+        host, *_ = params
 
         if host == "HOST":
             raise DataError("HOST is not yet supported in opera.")
         if host != "SELF":
             raise DataError(
-                "Attribute host should be set to 'SELF' which is the only "
-                "valid value. This is needed to indicate that the attribute "
-                "is referenced locally from something in the node itself."
+                "Attribute host should be set to 'SELF' which is the only valid value. This is needed to indicate that "
+                "the attribute is referenced locally from something in the node itself."
             )
         if len(self.instances) != 1:
             raise DataError("Cannot get an attribute from multiple instances")
@@ -168,20 +152,18 @@ def get_input(self, params):
         return self.topology.get_input(params)
 
     def map_attribute(self, params, value):
-        host, prop, *rest = params
+        host, *_ = params
 
         if host == "HOST":
             raise DataError("HOST is not yet supported in opera.")
         if host != "SELF":
             raise DataError(
-                "Attribute host should be set to 'SELF' which is the only "
-                "valid value. This is needed to indicate that the attribute "
-                "is referenced locally from something in the node itself."
+                "Attribute host should be set to 'SELF' which is the only valid value. This is needed to indicate that "
+                "the attribute is referenced locally from something in the node itself."
             )
 
         if len(self.instances) != 1:
-            raise DataError(
-                "Mapping an attribute for multiple instances not supported")
+            raise DataError("Mapping an attribute for multiple instances not supported")
 
         next(iter(self.instances.values())).map_attribute(params, value)
 
@@ -201,18 +183,15 @@ def get_artifact(self, params):
             raise DataError("HOST is not yet supported in opera.")
         if host != "SELF":
             raise DataError(
-                "Artifact host should be set to 'SELF' which is the only "
-                "valid value. This is needed to indicate that the artifact "
-                "is referenced locally from something in the node itself."
+                "Artifact host should be set to 'SELF' which is the only valid value. This is needed to indicate that "
+                "the artifact is referenced locally from something in the node itself."
             )
 
         if location == "LOCAL_FILE":
-            raise DataError("Location get_artifact property is "
-                            "not yet supported in opera.")
+            raise DataError("Location get_artifact property is not yet supported in opera.")
 
         if remove:
-            raise DataError("Remove get_artifact property artifacts is "
-                            "not yet supported in opera.")
+            raise DataError("Remove get_artifact property artifacts is not yet supported in opera.")
 
         if prop in self.artifacts:
             self.artifacts[prop].eval(self, prop)
diff --git a/src/opera/template/operation.py b/src/opera/template/operation.py
index 3ef05ec5..19a0169d 100644
--- a/src/opera/template/operation.py
+++ b/src/opera/template/operation.py
@@ -15,9 +15,7 @@ def __init__(self, name, primary, dependencies, artifacts, inputs, outputs, time
         self.host = host
 
     def run(self, host, instance, verbose, workdir):
-        thread_utils.print_thread(
-            "    Executing {} on {}".format(self.name, instance.tosca_id)
-        )
+        thread_utils.print_thread("    Executing {} on {}".format(self.name, instance.tosca_id))
 
         # TODO(@tadeboro): Respect the timeout option.
         # TODO(@tadeboro): Add host validation.
@@ -33,9 +31,7 @@ def run(self, host, instance, verbose, workdir):
         else:  # ORCHESTRATOR
             actual_host = "localhost"
 
-        operation_inputs = {
-            k: v.eval(instance, k) for k, v in self.inputs.items()
-        }
+        operation_inputs = {k: v.eval(instance, k) for k, v in self.inputs.items()}
 
         # TODO(@tadeboro): Generalize executors.
         success, ansible_outputs = ansible.run(
@@ -59,7 +55,6 @@ def run(self, host, instance, verbose, workdir):
 
         if len(unresolved_outputs) > 0:
             raise DataError(
-                "Operation did not return the following outputs: {}".format(
-                    ", ".join(unresolved_outputs)))
+                "Operation did not return the following outputs: {}".format(", ".join(unresolved_outputs)))
 
         return success, outputs, ansible_outputs
diff --git a/src/opera/template/relationship.py b/src/opera/template/relationship.py
index 27e435ea..f387ece4 100644
--- a/src/opera/template/relationship.py
+++ b/src/opera/template/relationship.py
@@ -1,5 +1,8 @@
+from typing import Dict
+
 from opera.error import DataError
 from opera.instance.relationship import Relationship as Instance
+from opera.template.topology import Topology
 
 
 class Relationship:
@@ -11,10 +14,10 @@ def __init__(self, name, types, properties, attributes, interfaces):
         self.interfaces = interfaces
 
         # This will be set when the relationship is inserted into a topology
-        self.topology = None
+        self.topology: Topology = None
 
         # This will be set at instantiation time.
-        self.instances = None
+        self.instances: Dict = None  # type: ignore
 
     def is_a(self, typ):
         return typ in self.types
@@ -24,8 +27,7 @@ def instantiate(self, source, target):
         self.instances = {relationship_id: Instance(self, relationship_id, source, target)}
         return self.instances.values()
 
-    def run_operation(self, host, interface, operation, instance, verbose,
-                      workdir):
+    def run_operation(self, host, interface, operation, instance, verbose, workdir):
         operation = self.interfaces[interface].operations.get(operation)
         if operation:
             return operation.run(host, instance, verbose, workdir)
@@ -35,15 +37,14 @@ def run_operation(self, host, interface, operation, instance, verbose,
     # TOSCA functions
     #
     def get_property(self, params):
-        host, prop, *rest = params
+        host, prop, *_ = params
 
         if host == "HOST":
             raise DataError("HOST is not yet supported in opera.")
         if host != "SELF":
             raise DataError(
-                "Property host should be set to 'SELF' which is the only "
-                "valid value. This is needed to indicate that the property is "
-                "referenced locally from something in the node itself."
+                "Property host should be set to 'SELF' which is the only valid value. This is needed to indicate that "
+                "the property is referenced locally from something in the node itself."
             )
 
         # TODO(@tadeboro): Add support for nested property values once we
@@ -54,15 +55,14 @@ def get_property(self, params):
         return self.properties[prop].eval(self, prop)
 
     def get_attribute(self, params):
-        host, attr, *rest = params
+        host, attr, *_ = params
 
         if host == "HOST":
             raise DataError("HOST is not yet supported in opera.")
         if host != "SELF":
             raise DataError(
-                "Attribute host should be set to 'SELF' which is the only "
-                "valid value. This is needed to indicate that the attribute "
-                "is referenced locally from something in the node itself."
+                "Attribute host should be set to 'SELF' which is the only valid value. This is needed to indicate that "
+                "the attribute is referenced locally from something in the node itself."
             )
 
         if attr not in self.attributes:
@@ -82,15 +82,12 @@ def get_input(self, params):
         return self.topology.get_input(params)
 
     def map_attribute(self, params, value):
-        host, prop, *rest = params
+        host, *_ = params
 
         if host not in ("SELF", "SOURCE", "TARGET"):
-            raise DataError(
-                "Attribute host should be set to 'SELF', 'SOURCE' or 'TARGET'."
-            )
+            raise DataError("Attribute host should be set to 'SELF', 'SOURCE' or 'TARGET'.")
 
         if len(self.instances) != 1:
-            raise DataError(
-                "Mapping an attribute for multiple instances not supported")
+            raise DataError("Mapping an attribute for multiple instances not supported")
 
         next(iter(self.instances.values())).map_attribute(params, value)
diff --git a/src/opera/template/topology.py b/src/opera/template/topology.py
index d3259f4e..86131517 100644
--- a/src/opera/template/topology.py
+++ b/src/opera/template/topology.py
@@ -30,11 +30,9 @@ def resolve_relationships(self):
                     self.relationships[relationship.name] = relationship
 
     def instantiate(self, storage):
-        return Instance(storage, itertools.chain.from_iterable(
-            node.instantiate() for node in self.nodes.values()
-        ))
+        return Instance(storage, itertools.chain.from_iterable(node.instantiate() for node in self.nodes.values()))
 
-    def get_outputs(self):
+    def get_outputs(self) -> dict:
         return {
             k: dict(
                 description=v["description"],
@@ -47,23 +45,18 @@ def find_node_or_relationship(self, entity_name):
         relationship = self.find_relationship(entity_name)
 
         if not node and not relationship:
-            raise DataError(
-                "Node template or relationship template "
-                "'{}' does not exist.".format(entity_name),
-            )
+            raise DataError("Node template or relationship template '{}' does not exist.".format(entity_name))
 
         if node and relationship:
             if node.name == relationship.name:
-                raise DataError(
-                    "Node template and relationship template "
-                    "'{}' should not have the same name.".format(entity_name),
-                )
+                raise DataError("Node template and relationship template '{}' should not have the same name."
+                                .format(entity_name))
 
         if node:
             return node
-
         if relationship:
             return relationship
+        return None
 
     def find_node(self, node_name):
         if node_name not in self.nodes:
@@ -106,16 +99,14 @@ def get_artifact(self, params):
 
     def concat(self, params, node=None):
         if not isinstance(params, list):
-            raise DataError("Concat intrinsic function parameters '{}'"
-                            " should be a list".format(params))
+            raise DataError("Concat intrinsic function parameters '{}' should be a list".format(params))
 
         return self.join([params], node)
 
     def join(self, params, node=None):
         if 1 <= len(params) <= 2:
             if not isinstance(params[0], list):
-                raise DataError("Concat or join intrinsic function parameters "
-                                "'{}' should be a list".format(params))
+                raise DataError("Concat or join intrinsic function parameters '{}' should be a list".format(params))
 
             string_value_expressions = params[0]
             delimiter = "" if len(params) == 1 else params[1]
@@ -129,9 +120,8 @@ def join(self, params, node=None):
                 if isinstance(param, dict):
                     param_dict_keys = list(param.keys())
                     if len(param_dict_keys) > 1:
-                        raise DataError(
-                            "Dict value expression for concat or join "
-                            "function has too many keys: '{}'".format(param))
+                        raise DataError("Dict value expression for concat or join function has too many keys: '{}'"
+                                        .format(param))
 
                     value_expression_name = param_dict_keys[0]
                     try:
@@ -139,57 +129,47 @@ def join(self, params, node=None):
                         values_to_join.append(
                             getattr(entity, value_expression_name)(
                                 param[value_expression_name]))
-                    except Exception:
-                        raise DataError(
-                            "Invalid value expression for concat or join "
-                            "function: '{}'".format(value_expression_name))
+                    except TypeError as e:
+                        raise DataError("Invalid value expression for concat or join function: '{}'"
+                                        .format(value_expression_name)) from e
                 elif isinstance(param, str):
                     values_to_join.append(param)
                 else:
-                    raise DataError(
-                        "Invalid value for concat or join function function: "
-                        "'{}'".format(param))
+                    raise DataError("Invalid value for concat or join function function: '{}'".format(param))
 
             return delimiter.join(values_to_join)
         else:
-            raise DataError("Too many or too less parameters for: '{}'. Join "
-                            "or concat intrinsic functions can only receive "
-                            "one or two parameters.".format(params))
+            raise DataError(
+                "Too many or too less parameters for: '{}'. Join or concat intrinsic functions can only receive "
+                "one or two parameters.".format(params)
+            )
 
-    def token(self, params):
+    @staticmethod
+    def token(params):
         if isinstance(params, list) and len(params) == 3:
             string_with_tokens = params[0]
             string_of_token_chars = params[1]
             substring_index = params[2]
 
             if not isinstance(string_with_tokens, str):
-                raise DataError(
-                    "String with tokens: '{}' should be a string!".format(
-                        string_with_tokens))
+                raise DataError("String with tokens: '{}' should be a string!".format(string_with_tokens))
 
             if not isinstance(string_of_token_chars, str):
-                raise DataError(
-                    "String of token chars: '{}' should be a string!".format(
-                        string_of_token_chars))
+                raise DataError("String of token chars: '{}' should be a string!".format(string_of_token_chars))
 
             if not isinstance(substring_index, int):
-                raise DataError(
-                    "Substring index: '{}' should be an integer!".format(
-                        substring_index))
+                raise DataError("Substring index: '{}' should be an integer!".format(substring_index))
 
             if string_of_token_chars not in string_with_tokens:
-                raise DataError(
-                    "Token: '{}' is not present in string '{}'.".format(
-                        string_of_token_chars, string_with_tokens))
+                raise DataError("Token: '{}' is not present in string '{}'.".format(string_of_token_chars,
+                                                                                    string_with_tokens))
 
             substrings = string_with_tokens.split(string_of_token_chars)
 
             if not 0 <= substring_index < len(substrings):
-                raise DataError("Substring index '{}' for token function "
-                                "does not exist.".format(substring_index))
+                raise DataError("Substring index '{}' for token function does not exist.".format(substring_index))
 
             return substrings[substring_index]
         else:
-            raise DataError(
-                "Too many or too less parameters for: '{}'. Token intrinsic "
-                "function requires exactly three parameters.".format(params))
+            raise DataError("Too many or too less parameters for: '{}'. Token intrinsic function requires exactly "
+                            "three parameters.".format(params))
diff --git a/src/opera/threading/__init__.py b/src/opera/threading/__init__.py
index ce674744..39854a0f 100644
--- a/src/opera/threading/__init__.py
+++ b/src/opera/threading/__init__.py
@@ -1,3 +1,3 @@
-from opera.threading.node_executor import (
+from opera.threading.node_executor import (  # noqa: F401
     NodeExecutor
 )
diff --git a/src/opera/threading/node_executor.py b/src/opera/threading/node_executor.py
index 9215fe28..45f3f0c4 100644
--- a/src/opera/threading/node_executor.py
+++ b/src/opera/threading/node_executor.py
@@ -1,7 +1,9 @@
 from concurrent.futures import ThreadPoolExecutor, wait
+from concurrent.futures._base import CancelledError
+
 from opera.error import OperationError
 
-WORKER_PREFIX = 'Worker'
+WORKER_PREFIX = "Worker"
 
 
 class NodeExecutor(ThreadPoolExecutor):
@@ -15,8 +17,7 @@ def __init__(self, num_workers=None):
         self.num_workers = num_workers
 
     def can_submit(self, node_id):
-        return (len(self.processed_nodes) < self.num_workers
-                and node_id not in self.processed_nodes)
+        return len(self.processed_nodes) < self.num_workers and node_id not in self.processed_nodes
 
     def submit_operation(self, operation, node_id, verbose, workdir):
         self.processed_nodes.add(node_id)
@@ -35,20 +36,15 @@ def wait_results(self):
             # if errors occurred
             # try cancel pending futures
             running = []
-            for fut in self.futures.keys():
+            for fut in self.futures:
                 if not fut.cancel():
                     running.append(fut)
             # wait for all running operations to complete
             # and halt execution
-            results = wait(
-                running,
-                return_when="ALL_COMPLETED"
-            )
+            results = wait(running, return_when="ALL_COMPLETED")
             errors.update(self.process_results(results))
             for node_id in errors:
-                print("Error processing node {0}: {1}".format(
-                    node_id, errors[node_id])
-                )
+                print("Error processing node {0}: {1}".format(node_id, errors[node_id]))
             raise OperationError("Failed")
 
         return proceed
@@ -60,7 +56,7 @@ def process_results(self, results):
             try:
                 future.result()
                 self.processed_nodes.remove(node_id)
-            except Exception as e:
+            except (CancelledError, TimeoutError) as e:
                 errors[node_id] = e
 
         return errors
diff --git a/src/opera/threading/utils.py b/src/opera/threading/utils.py
index d1d038b3..636d2487 100644
--- a/src/opera/threading/utils.py
+++ b/src/opera/threading/utils.py
@@ -1,5 +1,5 @@
-from threading import current_thread
+from threading import current_thread  # type: ignore # pylint: disable=no-name-in-module
 
 
-def print_thread(str):
-    print("[{}] {}".format(current_thread().name, str))
+def print_thread(string):
+    print("[{}] {}".format(current_thread().name, string))
diff --git a/src/opera/utils.py b/src/opera/utils.py
index 8c4a0436..95dfca15 100644
--- a/src/opera/utils.py
+++ b/src/opera/utils.py
@@ -1,20 +1,21 @@
-import yaml
 import json
-
-from zipfile import is_zipfile
-from tarfile import is_tarfile
-from uuid import uuid4
 from os import path
 from pathlib import Path, PurePath
+from tarfile import is_tarfile
+from uuid import uuid4
+from zipfile import is_zipfile
 
-from opera.parser import tosca
+import yaml
 
+from opera.parser import tosca
 
-def prompt_yes_no_question(yes_responses=("y", "yes"),
-                           no_responses=("n", "no"),
-                           case_sensitive=False,
-                           default_yes_response=True):
 
+def prompt_yes_no_question(
+        yes_responses=("y", "yes"),
+        no_responses=("n", "no"),
+        case_sensitive=False,
+        default_yes_response=True
+):
     prompt_message = "Do you want to continue? (Y/n): "
     if not default_yes_response:
         prompt_message = "Do you want to continue? (y/N): "
@@ -32,12 +33,10 @@ def prompt_yes_no_question(yes_responses=("y", "yes"),
             return False
         else:
             print("Invalid input. Please try again.")
-            return prompt_yes_no_question(yes_responses, no_responses,
-                                          case_sensitive, default_yes_response)
-    except Exception as e:
+            return prompt_yes_no_question(yes_responses, no_responses, case_sensitive, default_yes_response)
+    except EOFError as e:
         print("Exception occurred: {}. Please enter valid inputs.".format(e))
-        return prompt_yes_no_question(yes_responses, no_responses,
-                                      case_sensitive, default_yes_response)
+        return prompt_yes_no_question(yes_responses, no_responses, case_sensitive, default_yes_response)
 
 
 def determine_archive_format(filepath):
@@ -46,8 +45,9 @@ def determine_archive_format(filepath):
     elif is_zipfile(filepath):
         return "zip"
     else:
-        raise Exception("Unsupported archive format: '{}'. The packaging "
-                        "format should be one of: zip, tar.".format(filepath))
+        raise Exception(
+            "Unsupported archive format: '{}'. The packaging format should be one of: zip, tar.".format(filepath)
+        )
 
 
 def generate_random_pathname(prefix=""):
@@ -59,23 +59,23 @@ def generate_random_pathname(prefix=""):
         return pathname
 
 
-def format_outputs(outputs, format):
-    if format == "json":
+def format_outputs(outputs, outputs_format):
+    if outputs_format == "json":
         return json.dumps(outputs, indent=2)
-    if format == "yaml":
+    if outputs_format == "yaml":
         return yaml.safe_dump(outputs, default_flow_style=False)
 
-    assert False, "BUG - invalid format"
+    raise AssertionError("BUG - invalid format")
 
 
-def save_outputs(outputs, format, filename):
-    with open(filename, 'w+') as outfile:
-        if format == "json":
-            return json.dumps(outputs, outfile, indent=2)
-        if format == "yaml":
+def save_outputs(outputs, outputs_format, filename):
+    with open(filename, "w+") as outfile:
+        if outputs_format == "json":
+            return json.dump(outputs, outfile, indent=2)
+        if outputs_format == "yaml":
             return yaml.safe_dump(outputs, outfile, default_flow_style=False)
 
-        assert False, "BUG - invalid format"
+        raise AssertionError("BUG - invalid format")
 
 
 def get_workdir(storage):
@@ -97,8 +97,7 @@ def get_template(storage):
 
         if storage.exists("csars"):
             csar_dir = Path(storage.path) / "csars" / "csar"
-            ast = tosca.load(Path(csar_dir),
-                             PurePath(service_template).relative_to(csar_dir))
+            ast = tosca.load(Path(csar_dir), PurePath(service_template).relative_to(csar_dir))
         else:
             ast = tosca.load(Path.cwd(), PurePath(service_template))
 
diff --git a/src/opera/value.py b/src/opera/value.py
index 2cff3a24..2589bde5 100644
--- a/src/opera/value.py
+++ b/src/opera/value.py
@@ -28,7 +28,8 @@ def load(self, data):
 
     @property
     def data(self):
-        assert self.present, "Accessing an unset value. Bug-fixing ahead ;)"
+        if not self.present:
+            raise AssertionError("Accessing an unset value. Bug-fixing ahead ;)")
         return self._data
 
     def copy(self):
@@ -52,11 +53,7 @@ def eval(self, instance, key):
 
     @property
     def is_function(self):
-        return (
-            isinstance(self.data, dict) and
-            len(self.data) == 1 and
-            tuple(self.data.keys())[0] in self.FUNCTIONS
-        )
+        return isinstance(self.data, dict) and len(self.data) == 1 and tuple(self.data.keys())[0] in self.FUNCTIONS
 
     def eval_function(self, instance):
         (function_name, params), = self.data.items()


Test patch:
diff --git a/tests/integration/cli_commands/inputs.json b/tests/integration/cli_commands/inputs.json
index fa347b51..c6c431e9 100644
--- a/tests/integration/cli_commands/inputs.json
+++ b/tests/integration/cli_commands/inputs.json
@@ -1,4 +1,4 @@
 {
-  "test_attribute_input": 10,
-  "test_property_input": true
-}
\ No newline at end of file
+    "test_attribute_input": 10,
+    "test_property_input": true
+}
diff --git a/tests/integration/cli_commands/runme.sh b/tests/integration/cli_commands/runme.sh
index 4a68f085..f217cfb8 100755
--- a/tests/integration/cli_commands/runme.sh
+++ b/tests/integration/cli_commands/runme.sh
@@ -117,18 +117,18 @@ test "$(echo "$info_out" | jq -r .status)" = "undeployed"
 
 # move to the root of the extracted CSAR and
 # deploy the extracted service template with inputs
-cd unpacked-csar
-$opera_executable deploy --inputs ../inputs.yaml service.yaml
+(
+    cd unpacked-csar
+    set -euo pipefail
+    $opera_executable deploy --inputs ../inputs.yaml service.yaml
 
-# test opera info status after deploy
-info_out="$($opera_executable info --format json)"
-test "$(echo "$info_out" | jq -r .status)" = "deployed"
+    # test opera info status after deploy
+    info_out="$($opera_executable info --format json)"
+    test "$(echo "$info_out" | jq -r .status)" = "deployed"
+)
 
-# move one level up and remove the extracted folder
-cd ..
 rm -rf unpacked-csar
 
-
 # test opera commands on CSAR
 # prepare new opera storage folder
 mkdir -p ./csar-test-dir
diff --git a/tests/integration/compare/template1.yaml b/tests/integration/compare/template1.yaml
index f9585b4d..6170d4ff 100644
--- a/tests/integration/compare/template1.yaml
+++ b/tests/integration/compare/template1.yaml
@@ -1,76 +1,75 @@
-
 tosca_definitions_version: tosca_simple_yaml_1_3
 
 imports:
-- types.yaml
+  - types.yaml
 
 topology_template:
-    inputs:
-        marker:
-            type: string
-            default: default-marker
+  inputs:
+    marker:
+      type: string
+      default: default-marker
 
-    node_templates:
-        my-workstation:
-            type: tosca.nodes.Compute
-            attributes:
-                private_address: localhost
-                public_address: localhost
+  node_templates:
+    my-workstation:
+      type: tosca.nodes.Compute
+      attributes:
+        private_address: localhost
+        public_address: localhost
 
-        hello-1:
-            type: hello_type
-            properties:
-                time: "0"
-            artifacts:
-                def_file:
-                    type: tosca.artifacts.File
-                    file: files/file1_1.yaml
-            capabilities:
-                test:
-                    properties:
-                        test1: "2"
-                        test2: "2"
-            requirements:
-                - host: my-workstation
+    hello-1:
+      type: hello_type
+      properties:
+        time: "0"
+      artifacts:
+        def_file:
+          type: tosca.artifacts.File
+          file: files/file1_1.yaml
+      capabilities:
+        test:
+          properties:
+            test1: "2"
+            test2: "2"
+      requirements:
+        - host: my-workstation
 
-        hello-2:
-            type: hello_type_old
-            properties:
-                time: "0"
-            artifacts:
-                def_file:
-                    type: tosca.artifacts.File
-                    file: files/file1_1.yaml
-            capabilities:
-                test:
-                    properties:
-                        test1: "2"
-                        test2: "2"
-            requirements:
-                - host: my-workstation
+    hello-2:
+      type: hello_type_old
+      properties:
+        time: "0"
+      artifacts:
+        def_file:
+          type: tosca.artifacts.File
+          file: files/file1_1.yaml
+      capabilities:
+        test:
+          properties:
+            test1: "2"
+            test2: "2"
+      requirements:
+        - host: my-workstation
 
-        hello-3:
-            type: hello_type
-            properties:
-                time: "0"
-            requirements:
-                - host: my-workstation
+    hello-3:
+      type: hello_type
+      properties:
+        time: "0"
+      requirements:
+        - host: my-workstation
 
-        hello-4:
-            type: hello_type
-            properties:
-                time: "0"
-            requirements:
-                - host: my-workstation
+    hello-4:
+      type: hello_type
+      properties:
+        time: "0"
+      requirements:
+        - host: my-workstation
 
-        hello-6:
-            type: hello_type
-            properties:
-                time: "0"
-            artifacts:
-                def_file:
-                    type: tosca.artifacts.File
-                    file: files/file2.yaml
-            requirements:
-                - dependency: hello-1
-                - host: my-workstation
+    hello-6:
+      type: hello_type
+      properties:
+        time: "0"
+      artifacts:
+        def_file:
+          type: tosca.artifacts.File
+          file: files/file2.yaml
+      requirements:
+        - dependency: hello-1
+        - host: my-workstation
diff --git a/tests/integration/compare/template2.yaml b/tests/integration/compare/template2.yaml
index 26dffcc1..85447f7a 100644
--- a/tests/integration/compare/template2.yaml
+++ b/tests/integration/compare/template2.yaml
@@ -1,72 +1,71 @@
-
 tosca_definitions_version: tosca_simple_yaml_1_3
 
 imports:
-- types.yaml
+  - types.yaml
 
 topology_template:
-    inputs:
-        marker:
-            type: string
-            default: default-marker2
+  inputs:
+    marker:
+      type: string
+      default: default-marker2
 
-    node_templates:
-        my-workstation:
-            type: tosca.nodes.Compute
-            attributes:
-                private_address: localhost
-                public_address: localhost
+  node_templates:
+    my-workstation:
+      type: tosca.nodes.Compute
+      attributes:
+        private_address: localhost
+        public_address: localhost
 
-        hello-1:
-            type: hello_type
-            properties:
-                time: "1"
-            artifacts:
-                def_file:
-                    type: tosca.artifacts.File
-                    file: files/file1_2.yaml
-            requirements:
-                - host: my-workstation
+    hello-1:
+      type: hello_type
+      properties:
+        time: "1"
+      artifacts:
+        def_file:
+          type: tosca.artifacts.File
+          file: files/file1_2.yaml
+      requirements:
+        - host: my-workstation
 
-        hello-2:
-            type: hello_type_new
-            properties:
-                time: "0"
-            artifacts:
-                def_file:
-                    type: tosca.artifacts.File
-                    file: files/file2.yaml
-            capabilities:
-                test:
-                    properties:
-                        test1: "3"
-                        test2: "3"
-            requirements:
-                - dependency: hello-1
-                - host: my-workstation
+    hello-2:
+      type: hello_type_new
+      properties:
+        time: "0"
+      artifacts:
+        def_file:
+          type: tosca.artifacts.File
+          file: files/file2.yaml
+      capabilities:
+        test:
+          properties:
+            test1: "3"
+            test2: "3"
+      requirements:
+        - dependency: hello-1
+        - host: my-workstation
 
-        hello-3:
-            type: hello_type
-            properties:
-                time: "0"
-            requirements:
-                - host: my-workstation
+    hello-3:
+      type: hello_type
+      properties:
+        time: "0"
+      requirements:
+        - host: my-workstation
 
-        hello-5:
-            type: hello_type
-            properties:
-                time: "0"
-            requirements:
-                - host: my-workstation
+    hello-5:
+      type: hello_type
+      properties:
+        time: "0"
+      requirements:
+        - host: my-workstation
 
-        hello-6:
-            type: hello_type
-            properties:
-                time: "0"
-            artifacts:
-                def_file:
-                    type: tosca.artifacts.File
-                    file: files/file2.yaml
-            requirements:
-                - dependency: hello-2
-                - host: my-workstation
+    hello-6:
+      type: hello_type
+      properties:
+        time: "0"
+      artifacts:
+        def_file:
+          type: tosca.artifacts.File
+          file: files/file2.yaml
+      requirements:
+        - dependency: hello-2
+        - host: my-workstation
diff --git a/tests/integration/compare/types.yaml b/tests/integration/compare/types.yaml
index 5a8ab01a..79b895ee 100644
--- a/tests/integration/compare/types.yaml
+++ b/tests/integration/compare/types.yaml
@@ -1,4 +1,3 @@
-
 tosca_definitions_version: tosca_simple_yaml_1_3
 
 capability_types:
diff --git a/tests/integration/concurrency/service.yaml b/tests/integration/concurrency/service.yaml
index ce42a40f..6934ddd3 100644
--- a/tests/integration/concurrency/service.yaml
+++ b/tests/integration/concurrency/service.yaml
@@ -5,14 +5,14 @@ node_types:
     derived_from: tosca.nodes.SoftwareComponent
     properties:
       time:
-        default: "1" 
-        type: string     
+        default: "1"
+        type: string
     interfaces:
       Standard:
         inputs:
           time:
-            default: { get_property: [SELF, time] } 
-            type: string            
+            default: { get_property: [SELF, time] }
+            type: string
         operations:
           create: playbooks/sleep.yaml
           start: playbooks/sleep.yaml
@@ -43,22 +43,22 @@ topology_template:
       properties:
         time: "5"
       requirements:
-        - host: my-workstation     
-        
+        - host: my-workstation
+
     hello-3:
       type: hello_type
       properties:
         time: "1"
       requirements:
-        - host: my-workstation     
-        
+        - host: my-workstation
+
     hello-4:
       type: hello_type
       properties:
         time: "1"
       requirements:
-        - host: my-workstation         
-        
+        - host: my-workstation
+
     hello-5:
       type: hello_type
       properties:
@@ -73,14 +73,14 @@ topology_template:
         time: "1"
       requirements:
         - host: my-workstation
-        - dependency:  hello-5            
+        - dependency:  hello-5
 
     hello-7:
       type: hello_type
       properties:
         time: "3"
       requirements:
-        - host: my-workstation     
+        - host: my-workstation
         - dependency:  hello-6
 
     hello-8:
@@ -95,15 +95,15 @@ topology_template:
       properties:
         time: "1"
       requirements:
-        - host: my-workstation     
-        
+        - host: my-workstation
+
     hello-10:
       type: hello_type
       properties:
         time: "3"
       requirements:
-        - host: my-workstation     
-        
+        - host: my-workstation
+
     hello-11:
       type: hello_type
       properties:
@@ -118,15 +118,15 @@ topology_template:
         time: "2"
       requirements:
         - host: my-workstation
-        - dependency:  hello-3            
+        - dependency:  hello-3
 
     hello-13:
       type: hello_type
       properties:
         time: "3"
       requirements:
-        - host: my-workstation     
-        - dependency:  hello-4        
+        - host: my-workstation
+        - dependency:  hello-4
 
     hello-14:
       type: hello_type
diff --git a/tests/integration/misc_tosca_types/runme.sh b/tests/integration/misc_tosca_types/runme.sh
index 3c405101..b11f15f3 100755
--- a/tests/integration/misc_tosca_types/runme.sh
+++ b/tests/integration/misc_tosca_types/runme.sh
@@ -59,5 +59,8 @@ cd unpacked-csar
 $opera_executable deploy -i inputs.yaml service-template.yaml
 $opera_executable info
 # number of created .opera folders should be 1
+# shellcheck disable=SC1117,SC2010
 opera_count=$(ls -aR . | grep -c "^\.opera$")
-if [ "$opera_count" -ne 1 ]; then exit 1; fi
+if [ "$opera_count" -ne 1 ]; then
+    exit 1
+fi
diff --git a/tests/integration/misc_tosca_types/service-template.yaml b/tests/integration/misc_tosca_types/service-template.yaml
index 2415e2f0..cc4f8ec3 100644
--- a/tests/integration/misc_tosca_types/service-template.yaml
+++ b/tests/integration/misc_tosca_types/service-template.yaml
@@ -30,7 +30,7 @@ repositories:
     url: https://github.com/xlab-si/xopera-opera
 
 dsl_definitions:
-    test: &test test123
+  test: &test test123
 
 topology_template:
   inputs:
diff --git a/tests/unit/opera/compare/conftest.py b/tests/unit/opera/compare/conftest.py
index baaf1c2d..50cc93f7 100644
--- a/tests/unit/opera/compare/conftest.py
+++ b/tests/unit/opera/compare/conftest.py
@@ -1,6 +1,7 @@
-import pytest
 import pathlib
 
+import pytest
+
 from opera.parser import tosca
 from opera.storage import Storage
 
@@ -8,6 +9,7 @@
 def setupdir(path, yaml_text):
     pathlib.Path.mkdir(path)
     pathlib.Path.mkdir(path / "files")
+    # language=yaml
     imports = \
         """
         tosca_definitions_version: tosca_simple_yaml_1_3
@@ -67,6 +69,7 @@ def setupdir(path, yaml_text):
                         default: "2"
                         type: string
         """
+    # language=yaml
     playbook = \
         """
         ---
@@ -76,10 +79,12 @@ def setupdir(path, yaml_text):
             - command:
                 cmd: sleep "{{ time }}"
         """
+    # language=yaml
     artefact1 = \
         """
         test: 1
         """
+    # language=yaml
     artefact2 = \
         """
         test: 2
@@ -103,10 +108,12 @@ def prepare_template(path, yaml_text, template):
     topology = template.instantiate(storage)
     return template, topology, path
 
+
 @pytest.fixture
 def service_template1(tmp_path, yaml_text):
     path = tmp_path / pathlib.Path("t1")
     setupdir(path, yaml_text)
+    # language=yaml
     template = \
         """
         tosca_definitions_version: tosca_simple_yaml_1_3
@@ -192,6 +199,7 @@ def service_template1(tmp_path, yaml_text):
 def service_template2(tmp_path, yaml_text):
     path = tmp_path / pathlib.Path("t2")
     setupdir(path, yaml_text)
+    # language=yaml
     template = \
         """
         tosca_definitions_version: tosca_simple_yaml_1_3
diff --git a/tests/unit/opera/compare/test_instance_compare.py b/tests/unit/opera/compare/test_instance_compare.py
index efbc55e1..a60b8fd6 100644
--- a/tests/unit/opera/compare/test_instance_compare.py
+++ b/tests/unit/opera/compare/test_instance_compare.py
@@ -1,29 +1,24 @@
 import pytest
 
-from opera.compare.template_comparer import TemplateComparer, TemplateContext
 from opera.compare.instance_comparer import InstanceComparer
+from opera.compare.template_comparer import TemplateComparer, TemplateContext
 
 
 class TestInstanceCompare:
     @pytest.fixture
-    def template_diff(self, service_template1,
-                      service_template2):
+    def template_diff(self, service_template1, service_template2):
         comparer = TemplateComparer()
         context = TemplateContext(service_template1[0],
                                   service_template2[0],
                                   service_template1[2],
                                   service_template2[2])
-        equal, diff = comparer.compare_service_template(service_template1[0],
-                                                        service_template2[0],
-                                                        context)
+        equal, diff = comparer.compare_service_template(service_template1[0], service_template2[0], context)
         return diff
 
     def test_node_state_comparison(self, service_template1,
                                    service_template2, template_diff):
         comparer = InstanceComparer()
-        equal, diff = comparer.compare_topology_template(service_template1[1],
-                                                         service_template2[1],
-                                                         template_diff)
+        equal, diff = comparer.compare_topology_template(service_template1[1], service_template2[1], template_diff)
         assert equal is False
         assert len(diff.changed["nodes"].changed) == 5
 
@@ -37,8 +32,7 @@ def test_node_state_comparison(self, service_template1,
         assert "state" in diff.changed["nodes"].changed["hello-2"].changed
         assert "state" in diff.changed["nodes"].changed["hello-3"].changed
         assert "state" in diff.changed["nodes"].changed["hello-6"].changed
-        assert "state" in diff.changed["nodes"] \
-            .changed["my-workstation"].changed
+        assert "state" in diff.changed["nodes"].changed["my-workstation"].changed
 
     def test_dependency_comparison(self, service_template1,
                                    service_template2, template_diff):
@@ -52,34 +46,22 @@ def test_dependency_comparison(self, service_template1,
         assert "hello-6" in diff.changed["nodes"].changed
         assert "my-workstation" in diff.changed["nodes"].changed
 
-        assert "dependencies" in diff.changed["nodes"] \
-            .changed["hello-6"].changed
-        assert "dependencies" in diff.changed["nodes"] \
-            .changed["hello-2"].changed
+        assert "dependencies" in diff.changed["nodes"].changed["hello-6"].changed
+        assert "dependencies" in diff.changed["nodes"].changed["hello-2"].changed
 
-        assert "dependencies" not in diff.changed["nodes"] \
-            .changed["hello-1"].changed
-        assert "dependencies" not in diff.changed["nodes"] \
-            .changed["hello-3"].changed
-        assert "dependencies" not in diff.changed["nodes"] \
-            .changed["my-workstation"].changed
+        assert "dependencies" not in diff.changed["nodes"].changed["hello-1"].changed
+        assert "dependencies" not in diff.changed["nodes"].changed["hello-3"].changed
+        assert "dependencies" not in diff.changed["nodes"].changed["my-workstation"].changed
 
-    def test_prepare_update(self, service_template1,
-                            service_template2, template_diff):
+    def test_prepare_update(self, service_template1, service_template2, template_diff):
         comparer = InstanceComparer()
         for node1 in service_template1[1].nodes.values():
             node1.set_state("started")
-        assert service_template2[1].nodes["my-workstation_0"] \
-            .state == "initial"
-        equal, diff = comparer.compare_topology_template(service_template1[1],
-                                                         service_template2[1],
-                                                         template_diff)
+        assert service_template2[1].nodes["my-workstation_0"].state == "initial"
+
+        equal, diff = comparer.compare_topology_template(service_template1[1], service_template2[1], template_diff)
         assert equal is False
-        comparer.prepare_update(service_template1[1],
-                                service_template2[1],
-                                diff)
 
-        assert service_template1[1].nodes["my-workstation_0"] \
-            .state == "initial"
-        assert service_template2[1].nodes["my-workstation_0"] \
-            .state == "started"
+        comparer.prepare_update(service_template1[1], service_template2[1], diff)
+        assert service_template1[1].nodes["my-workstation_0"].state == "initial"
+        assert service_template2[1].nodes["my-workstation_0"].state == "started"
diff --git a/tests/unit/opera/compare/test_template_compare.py b/tests/unit/opera/compare/test_template_compare.py
index 7d3bcb66..d59f3f9d 100644
--- a/tests/unit/opera/compare/test_template_compare.py
+++ b/tests/unit/opera/compare/test_template_compare.py
@@ -1,19 +1,14 @@
-import pytest
-
 from opera.compare.template_comparer import TemplateComparer, TemplateContext
 
 
 class TestTemplateCompare:
-    def test_service_template_comparison(self, service_template1,
-                                         service_template2):
+    def test_service_template_comparison(self, service_template1, service_template2):
         comparer = TemplateComparer()
         context = TemplateContext(service_template1[0],
                                   service_template2[0],
                                   service_template1[2],
                                   service_template2[2])
-        equal, diff = comparer.compare_service_template(service_template1[0],
-                                                        service_template2[0],
-                                                        context)
+        equal, diff = comparer.compare_service_template(service_template1[0], service_template2[0], context)
 
         assert equal is False
 
@@ -50,9 +45,7 @@ def test_node_comparison(self, service_template1,
 
         node1_2 = service_template1[0].get_node("hello-2")
         node2_2 = service_template2[0].get_node("hello-2")
-        context = TemplateContext(node1_2, node2_2,
-                                  service_template1[2],
-                                  service_template2[2])
+        context = TemplateContext(node1_2, node2_2, service_template1[2], service_template2[2])
         equal, diff = comparer._compare_node(node1_2, node2_2, context)
 
         assert equal is False
@@ -68,36 +61,28 @@ def test_requirement_comparison(self, service_template1,
         comparer = TemplateComparer()
         node1 = service_template1[0].get_node("hello-6")
         node2 = service_template2[0].get_node("hello-6")
-        context = TemplateContext(node1, node2,
-                                  service_template1[2],
-                                  service_template2[2])
+        context = TemplateContext(node1, node2, service_template1[2], service_template2[2])
         equal, diff = comparer._compare_node(node1, node2, context)
 
         assert equal is False
 
         assert "requirements" in diff.changed
         assert "dependency" in diff.changed["requirements"].changed
-        assert "target" in diff.changed["requirements"] \
-            .changed["dependency"].changed
+        assert "target" in diff.changed["requirements"].changed["dependency"].changed
 
     def test_interface_comparison(self, service_template1,
                                   service_template2):
         comparer = TemplateComparer()
         node1 = service_template1[0].get_node("hello-1")
         node2 = service_template2[0].get_node("hello-1")
-        context = TemplateContext(node1, node2,
-                                  service_template1[2],
-                                  service_template2[2])
+        context = TemplateContext(node1, node2, service_template1[2], service_template2[2])
         equal, diff = comparer._compare_node(node1, node2, context)
 
         assert equal is False
 
         assert "interfaces" in diff.changed
-        assert "create" in diff.changed["interfaces"] \
-            .changed["Standard"].changed["operations"].changed
-        assert "artifacts" in diff.changed["interfaces"] \
-            .changed["Standard"].changed["operations"] \
-            .changed["create"].changed
-        assert "inputs" in diff.changed["interfaces"] \
-            .changed["Standard"].changed["operations"] \
-            .changed["create"].changed
+        assert "create" in diff.changed["interfaces"].changed["Standard"].changed["operations"].changed
+        assert "artifacts" in \
+               diff.changed["interfaces"].changed["Standard"].changed["operations"].changed["create"].changed
+        assert "inputs" in \
+               diff.changed["interfaces"].changed["Standard"].changed["operations"].changed["create"].changed
diff --git a/tests/unit/opera/conftest.py b/tests/unit/opera/conftest.py
index f6e73689..3937ab9b 100644
--- a/tests/unit/opera/conftest.py
+++ b/tests/unit/opera/conftest.py
@@ -9,6 +9,7 @@
 def yaml_text():
     def _yaml_text(string_data):
         return textwrap.dedent(string_data)
+
     return _yaml_text
 
 
@@ -16,4 +17,5 @@ def _yaml_text(string_data):
 def yaml_ast():
     def _yaml_ast(string_data):
         return yaml.load(textwrap.dedent(string_data), "TEST")
+
     return _yaml_ast
diff --git a/tests/unit/opera/instance/test_attribute_mapping.py b/tests/unit/opera/instance/test_attribute_mapping.py
index 280ebc7f..64e7dda1 100644
--- a/tests/unit/opera/instance/test_attribute_mapping.py
+++ b/tests/unit/opera/instance/test_attribute_mapping.py
@@ -12,6 +12,7 @@ class TestAttributeMapping:
     def service_template(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -49,7 +50,7 @@ def service_template(self, tmp_path, yaml_text):
         storage.write("template.yaml", "root_file")
         ast = tosca.load(tmp_path, name)
         template = ast.get_template({})
-        topology = template.instantiate(storage)
+        template.instantiate(storage)
         yield template
 
     def test_map_attribute_node(self, service_template):
@@ -57,74 +58,64 @@ def test_map_attribute_node(self, service_template):
         node.map_attribute(["SELF", "colour"], "green")
         assert "green" == node.get_attribute(["SELF", "colour"])
 
-    @pytest.mark.parametrize("host",
-                             ["SOURCE", "TARGET", "HOST" "my_collector",
-                              "other"])
+    @pytest.mark.parametrize("host", ["SOURCE", "TARGET", "HOST" "my_collector", "other"])
     def test_map_attribute_node_bad_host(self, service_template, host):
         node = service_template.find_node("my_node")
-        with pytest.raises(DataError, match="Attribute host should be set to "
-                                            "'SELF'"):
-          node.map_attribute([host, "colour"], "black")
+        with pytest.raises(DataError, match="Attribute host should be set to 'SELF'"):
+            node.map_attribute([host, "colour"], "black")
 
     def test_map_attribute_node_bad_attribute(self, service_template):
         node = service_template.find_node("my_node")
         with pytest.raises(DataError, match="Cannot find attribute"):
-          node.map_attribute(["SELF", "volume"], "loud")
+            node.map_attribute(["SELF", "volume"], "loud")
 
     def test_map_attribute_relationship_source(self, service_template):
-      node_source = service_template.find_node("my_collector")
-      node_source_instance = next(iter(node_source.instances.values()))
-      relationship_instance = next(
-        iter(node_source_instance.out_edges["my_target"].values()))
+        node_source = service_template.find_node("my_collector")
+        node_source_instance = next(iter(node_source.instances.values()))
+        relationship_instance = next(iter(node_source_instance.out_edges["my_target"].values()))
 
-      relationship_instance.map_attribute(["SOURCE", "colour"], "ochre")
+        relationship_instance.map_attribute(["SOURCE", "colour"], "ochre")
 
-      assert "ochre" == node_source.get_attribute(["SELF", "colour"])
+        assert "ochre" == node_source.get_attribute(["SELF", "colour"])
 
     def test_map_attribute_relationship_target(self, service_template):
-      node_target = service_template.find_node("my_node")
-      node_source = service_template.find_node("my_collector")
-      node_source_instance = next(iter(node_source.instances.values()))
-      relationship_instance = next(
-        iter(node_source_instance.out_edges["my_target"].values()))
+        node_target = service_template.find_node("my_node")
+        node_source = service_template.find_node("my_collector")
+        node_source_instance = next(iter(node_source.instances.values()))
+        relationship_instance = next(iter(node_source_instance.out_edges["my_target"].values()))
 
-      relationship_instance.map_attribute(["TARGET", "colour"], "magenta")
+        relationship_instance.map_attribute(["TARGET", "colour"], "magenta")
 
-      assert "magenta" == node_target.get_attribute(["SELF", "colour"])
+        assert "magenta" == node_target.get_attribute(["SELF", "colour"])
 
     def test_map_attribute_relationship_self(self, service_template):
-      node_source = service_template.find_node("my_collector")
-      node_source_instance = next(iter(node_source.instances.values()))
-      relationship_instance = next(
-        iter(node_source_instance.out_edges["my_target"].values()))
+        node_source = service_template.find_node("my_collector")
+        node_source_instance = next(iter(node_source.instances.values()))
+        relationship_instance = next(iter(node_source_instance.out_edges["my_target"].values()))
 
-      relationship_instance.map_attribute(["SELF", "colour"], "steampunk")
+        relationship_instance.map_attribute(["SELF", "colour"], "steampunk")
 
-      assert "steampunk" == relationship_instance.get_attribute(
-          ["SELF", "colour"])
+        assert "steampunk" == relationship_instance.get_attribute(["SELF", "colour"])
 
     @pytest.mark.parametrize("host",
                              ["HOST", "my_node", "my_collector", "other"])
     def test_map_attribute_relationship_bad_host(self, service_template, host):
-      node_source = service_template.find_node("my_collector")
-      node_source_instance = next(iter(node_source.instances.values()))
-      relationship_instance = next(
-        iter(node_source_instance.out_edges["my_target"].values()))
+        node_source = service_template.find_node("my_collector")
+        node_source_instance = next(iter(node_source.instances.values()))
+        relationship_instance = next(iter(node_source_instance.out_edges["my_target"].values()))
 
-      with pytest.raises(DataError, match="Attribute host should be set to "
-                                          "'SELF'"):
-        relationship_instance.map_attribute([host, "colour"], "ochre")
+        with pytest.raises(DataError, match="Attribute host should be set to 'SELF'"):
+            relationship_instance.map_attribute([host, "colour"], "ochre")
 
     @pytest.mark.parametrize("host, pattern", [
-                                ("SELF", "Instance has no 'volume' attribute"),
-                                ("SOURCE", "Cannot find attribute 'volume'."),
-                                ("TARGET", "Cannot find attribute 'volume'.")
-                            ])
+        ("SELF", "Instance has no 'volume' attribute"),
+        ("SOURCE", "Cannot find attribute 'volume'."),
+        ("TARGET", "Cannot find attribute 'volume'.")
+    ])
     def test_map_attr_rel_bad_attr(self, service_template, host, pattern):
-      node_source = service_template.find_node("my_collector")
-      node_source_instance = next(iter(node_source.instances.values()))
-      relationship_instance = next(
-        iter(node_source_instance.out_edges["my_target"].values()))
+        node_source = service_template.find_node("my_collector")
+        node_source_instance = next(iter(node_source.instances.values()))
+        relationship_instance = next(iter(node_source_instance.out_edges["my_target"].values()))
 
-      with pytest.raises(DataError, match=pattern):
-        relationship_instance.map_attribute([host, "volume"], "quiet")
+        with pytest.raises(DataError, match=pattern):
+            relationship_instance.map_attribute([host, "volume"], "quiet")
diff --git a/tests/unit/opera/parser/test_tosca.py b/tests/unit/opera/parser/test_tosca.py
index 8aa11859..a81f8039 100644
--- a/tests/unit/opera/parser/test_tosca.py
+++ b/tests/unit/opera/parser/test_tosca.py
@@ -10,9 +10,7 @@
 class TestLoad:
     def test_load_minimal_document(self, tmp_path):
         name = pathlib.PurePath("root.yaml")
-        (tmp_path / name).write_text(
-            "tosca_definitions_version: tosca_simple_yaml_1_3",
-        )
+        (tmp_path / name).write_text("tosca_definitions_version: tosca_simple_yaml_1_3")
 
         doc = tosca.load(tmp_path, name)
         assert doc.tosca_definitions_version.data == "tosca_simple_yaml_1_3"
@@ -55,6 +53,7 @@ def test_stdlib_is_present(self, tmp_path, typ):
     def test_custom_type_is_present(self, tmp_path, yaml_text, typ):
         name = pathlib.PurePath("custom.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             {}:
@@ -69,6 +68,7 @@ def test_custom_type_is_present(self, tmp_path, yaml_text, typ):
     def test_loads_template_part(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             topology_template:
@@ -85,6 +85,7 @@ def test_load_from_csar_subfolder(self, tmp_path, yaml_text):
         name = pathlib.PurePath("sub/folder/file.yaml")
         (tmp_path / name).parent.mkdir(parents=True)
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             imports:
@@ -92,6 +93,7 @@ def test_load_from_csar_subfolder(self, tmp_path, yaml_text):
             """
         ))
         (tmp_path / "sub/folder/imp.yaml").write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             data_types:
@@ -106,6 +108,7 @@ def test_load_from_csar_subfolder(self, tmp_path, yaml_text):
     def test_duplicate_import(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             imports: [ template.yaml ]
@@ -116,6 +119,7 @@ def test_duplicate_import(self, tmp_path, yaml_text):
     def test_imports_from_multiple_levels(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             imports:
@@ -125,6 +129,7 @@ def test_imports_from_multiple_levels(self, tmp_path, yaml_text):
         ))
         (tmp_path / "subfolder").mkdir()
         (tmp_path / "subfolder/a.yaml").write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             imports:
@@ -132,6 +137,7 @@ def test_imports_from_multiple_levels(self, tmp_path, yaml_text):
             """
         ))
         (tmp_path / "subfolder/b.yaml").write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             data_types:
@@ -145,6 +151,7 @@ def test_imports_from_multiple_levels(self, tmp_path, yaml_text):
     def test_merge_topology_template(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             imports:
@@ -155,10 +162,11 @@ def test_merge_topology_template(self, tmp_path, yaml_text):
                   type: string
               node_templates:
                 my_node:
-                  type: tosca.nodes.SoftwareComponent              
+                  type: tosca.nodes.SoftwareComponent
             """
         ))
         (tmp_path / "merge.yaml").write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             topology_template:
@@ -167,7 +175,7 @@ def test_merge_topology_template(self, tmp_path, yaml_text):
                   type: string
               node_templates:
                 other_node:
-                  type: tosca.nodes.SoftwareComponent 
+                  type: tosca.nodes.SoftwareComponent
             """
         ))
         tosca.load(tmp_path, name)
@@ -175,6 +183,7 @@ def test_merge_topology_template(self, tmp_path, yaml_text):
     def test_merge_duplicate_node_templates_invalid(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             imports:
@@ -183,28 +192,30 @@ def test_merge_duplicate_node_templates_invalid(self, tmp_path, yaml_text):
             topology_template:
               node_templates:
                 my_node:
-                  type: tosca.nodes.SoftwareComponent              
+                  type: tosca.nodes.SoftwareComponent
             """
         ))
         (tmp_path / "merge1.yaml").write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             topology_template:
               node_templates:
                 other_node:
-                  type: tosca.nodes.SoftwareComponent 
+                  type: tosca.nodes.SoftwareComponent
             """
         ))
         (tmp_path / "merge2.yaml").write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             topology_template:
               node_templates:
                 other_node:
-                  type: tosca.nodes.SoftwareComponent 
+                  type: tosca.nodes.SoftwareComponent
             """
         ))
-        with pytest.raises(ParseError):        
+        with pytest.raises(ParseError):
             tosca.load(tmp_path, name)
 
 
@@ -212,6 +223,7 @@ class TestExecute:
     def test_undefined_required_properties1(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -235,19 +247,19 @@ def test_undefined_required_properties1(self, tmp_path, yaml_text):
             topology_template:
               node_templates:
                 my_node_template:
-                  type: my_node_type             
+                  type: my_node_type
             """
         ))
         storage = Storage(tmp_path / pathlib.Path(".opera"))
         storage.write("template.yaml", "root_file")
         ast = tosca.load(tmp_path, name)
-        with pytest.raises(ParseError, match="Missing a required property: "
-                                             "test_property3"):
+        with pytest.raises(ParseError, match="Missing a required property: test_property3"):
             ast.get_template({})
 
     def test_undefined_required_properties2(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -265,19 +277,19 @@ def test_undefined_required_properties2(self, tmp_path, yaml_text):
             topology_template:
               node_templates:
                 my_node_template:
-                  type: my_node_type             
+                  type: my_node_type
             """
         ))
         storage = Storage(tmp_path / pathlib.Path(".opera"))
         storage.write("template.yaml", "root_file")
         ast = tosca.load(tmp_path, name)
-        with pytest.raises(ParseError, match="Missing a required property: "
-                                             "test_prop3"):
+        with pytest.raises(ParseError, match="Missing a required property: test_prop3"):
             ast.get_template({})
 
     def test_undefined_required_properties3(self, tmp_path, yaml_text):
         name = pathlib.PurePath("template.yaml")
         (tmp_path / name).write_text(yaml_text(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -293,15 +305,14 @@ def test_undefined_required_properties3(self, tmp_path, yaml_text):
             topology_template:
               node_templates:
                 my_node_template:
-                  type: my_node_type  
+                  type: my_node_type
                   properties:
                     property1: 42
-                    property2: 42.0        
+                    property2: 42.0
             """
         ))
         storage = Storage(tmp_path / pathlib.Path(".opera"))
         storage.write("template.yaml", "root_file")
         ast = tosca.load(tmp_path, name)
-        with pytest.raises(ParseError, match="Missing a required property: "
-                                             "property3"):
+        with pytest.raises(ParseError, match="Missing a required property: property3"):
             ast.get_template({})
diff --git a/tests/unit/opera/parser/tosca/test_bool.py b/tests/unit/opera/parser/tosca/test_bool.py
index 3c5be6bb..b686566b 100644
--- a/tests/unit/opera/parser/tosca/test_bool.py
+++ b/tests/unit/opera/parser/tosca/test_bool.py
@@ -11,7 +11,7 @@ def test_with_bool_data(self, data):
         Bool.validate(Node(data))
 
     @pytest.mark.parametrize(
-        "data", [4,  (), (1, 2, 3), [], ["a", "b"], {}],
+        "data", [4, (), (1, 2, 3), [], ["a", "b"], {}],
     )
     def test_with_non_bool_data(self, data):
         with pytest.raises(ParseError):
diff --git a/tests/unit/opera/parser/tosca/test_entity.py b/tests/unit/opera/parser/tosca/test_entity.py
index ffc7976f..2d73af38 100644
--- a/tests/unit/opera/parser/tosca/test_entity.py
+++ b/tests/unit/opera/parser/tosca/test_entity.py
@@ -141,6 +141,7 @@ class Baddie(TypeEntity):
 class TestTypeEntityValidate:
     def test_valid_data(self, yaml_ast):
         Goodie.validate(yaml_ast(
+            # language=yaml
             """
             derived_from: my_parent_type
             description: My type description
@@ -152,6 +153,7 @@ def test_valid_data(self, yaml_ast):
     def test_missing_derived_from(self, yaml_ast):
         with pytest.raises(ParseError):
             Goodie.validate(yaml_ast(
+                # language=yaml
                 """
                 description: My type description
                 metadata: {}
diff --git a/tests/unit/opera/parser/tosca/test_integer.py b/tests/unit/opera/parser/tosca/test_integer.py
index 2ea2d7af..3f06ba91 100644
--- a/tests/unit/opera/parser/tosca/test_integer.py
+++ b/tests/unit/opera/parser/tosca/test_integer.py
@@ -9,9 +9,7 @@ class TestValidate:
     def test_with_int_data(self):
         Integer.validate(Node(1234))
 
-    @pytest.mark.parametrize(
-        "data", ["4",  (), (1, 2, 3), [], ["a", "b"], {}],
-    )
+    @pytest.mark.parametrize("data", ["4", (), (1, 2, 3), [], ["a", "b"], {}])
     def test_with_non_string(self, data):
         with pytest.raises(ParseError):
             Integer.validate(Node(data))
diff --git a/tests/unit/opera/parser/tosca/test_list.py b/tests/unit/opera/parser/tosca/test_list.py
index 6e6f4ff0..7f5f40a5 100644
--- a/tests/unit/opera/parser/tosca/test_list.py
+++ b/tests/unit/opera/parser/tosca/test_list.py
@@ -3,8 +3,8 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.list import List, ListWrapper
 from opera.parser.tosca.base import Base
+from opera.parser.tosca.list import List, ListWrapper
 from opera.parser.yaml.node import Node
 
 
@@ -42,6 +42,7 @@ class TestListWrapperIteration:
     def test_iteration(self):
         assert tuple(ListWrapper(["a", "b"], None)) == ("a", "b")
 
+
 class TestListWrapperDig:
     def test_single_level(self):
         assert ListWrapper(["a", "b"], None).dig(1) == "b"
diff --git a/tests/unit/opera/parser/tosca/test_map.py b/tests/unit/opera/parser/tosca/test_map.py
index 69d5460c..328e599c 100644
--- a/tests/unit/opera/parser/tosca/test_map.py
+++ b/tests/unit/opera/parser/tosca/test_map.py
@@ -3,8 +3,8 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.map import Map, MapWrapper, OrderedMap
 from opera.parser.tosca.base import Base
+from opera.parser.tosca.map import Map, MapWrapper, OrderedMap
 from opera.parser.yaml.node import Node
 
 
@@ -14,7 +14,7 @@ def test_lut_access_for_string_key(self):
 
     def test_test_non_string_key(self):
         with pytest.raises(KeyError):
-            assert MapWrapper({Base(1, None): "v" }, None)[1]
+            assert MapWrapper({Base(1, None): "v"}, None)[1]
 
 
 class TestMapWrapperIteration:
@@ -43,7 +43,7 @@ def test_items(self):
 
 class TestMapWrapperDig:
     def test_single_level(self):
-        assert MapWrapper({"k": "v" }, None).dig("k") == "v"
+        assert MapWrapper({"k": "v"}, None).dig("k") == "v"
 
     def test_multi_level(self):
         obj = MapWrapper({
@@ -63,10 +63,10 @@ def test_bad_index_type(self):
 
 class TestMapWrapperMerge:
     def test_merge(self):
-        map = MapWrapper({"a": 0}, None)
-        map.merge(MapWrapper({"b": 1}, None))
+        testmap = MapWrapper({"a": 0}, None)
+        testmap.merge(MapWrapper({"b": 1}, None))
 
-        assert map.data == dict(a=0, b=1)
+        assert testmap.data == dict(a=0, b=1)
 
     def test_duplicated_key(self):
         with pytest.raises(ParseError, match="twice"):
diff --git a/tests/unit/opera/parser/tosca/test_path.py b/tests/unit/opera/parser/tosca/test_path.py
index df5b72d5..4664c871 100644
--- a/tests/unit/opera/parser/tosca/test_path.py
+++ b/tests/unit/opera/parser/tosca/test_path.py
@@ -13,16 +13,16 @@ def test_build(self):
 
 
 class TestPrefixPath:
-    @pytest.mark.parametrize("input,prefix", [
+    @pytest.mark.parametrize("input_path,prefix", [
         ("/a/b", "c"), ("/a", "b"), ("/a", "../.."), ("/c", "."),
     ])
-    def test_prefix_absolute_path(self, input, prefix):
-        path = Path(pathlib.PurePath(input), None)
+    def test_prefix_absolute_path(self, input_path, prefix):
+        path = Path(pathlib.PurePath(input_path), None)
         path.prefix_path(pathlib.PurePath(prefix))
 
-        assert str(path.data) == input
+        assert str(path.data) == input_path
 
-    @pytest.mark.parametrize("input,prefix,output", [
+    @pytest.mark.parametrize("input_path,prefix,output", [
         ("a", "b", "b/a"),
         ("a", "..", "../a"),
         ("a", ".", "a"),
@@ -31,8 +31,8 @@ def test_prefix_absolute_path(self, input, prefix):
         ("a/b", "c/d", "c/d/a/b"),
         ("a", "c/d/", "c/d/a"),
     ])
-    def test_prefix_relative_path(self, input, prefix, output):
-        path = Path(pathlib.PurePath(input), None)
+    def test_prefix_relative_path(self, input_path, prefix, output):
+        path = Path(pathlib.PurePath(input_path), None)
         path.prefix_path(pathlib.PurePath(prefix))
 
         assert str(path.data) == output
diff --git a/tests/unit/opera/parser/tosca/test_reference.py b/tests/unit/opera/parser/tosca/test_reference.py
index 05883fe1..99eeeefe 100644
--- a/tests/unit/opera/parser/tosca/test_reference.py
+++ b/tests/unit/opera/parser/tosca/test_reference.py
@@ -1,9 +1,7 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.reference import (
-    DataTypeReference, DataTypeReferenceWrapper, Reference, ReferenceWrapper,
-)
+from opera.parser.tosca.reference import DataTypeReferenceWrapper, Reference, ReferenceWrapper
 from opera.parser.tosca.type import Type
 from opera.parser.tosca.v_1_3.service_template import ServiceTemplate
 from opera.parser.yaml.node import Node
@@ -11,7 +9,8 @@
 
 class TestReferenceWrapperResolveReference:
     def test_valid_type_reference(self, yaml_ast, tmp_path):
-        service = ServiceTemplate.parse(yaml_ast(
+        service = ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -25,7 +24,8 @@ def test_valid_type_reference(self, yaml_ast, tmp_path):
         assert service.node_types["my.Type"] == ref.resolve_reference(service)
 
     def test_valid_template_reference(self, yaml_ast, tmp_path):
-        service = ServiceTemplate.parse(yaml_ast(
+        service = ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             topology_template:
@@ -41,7 +41,8 @@ def test_valid_template_reference(self, yaml_ast, tmp_path):
         assert target == ref.resolve_reference(service)
 
     def test_invalid_reference(self, yaml_ast, tmp_path):
-        service = ServiceTemplate.parse(yaml_ast(
+        service = ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -72,7 +73,8 @@ def test_valid_internal_data_type_reference(self, typ):
         assert typ == result.data
 
     def test_valid_user_data_type_reference(self, yaml_ast, tmp_path):
-        service = ServiceTemplate.parse(yaml_ast(
+        service = ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             data_types:
diff --git a/tests/unit/opera/parser/tosca/test_string.py b/tests/unit/opera/parser/tosca/test_string.py
index a0e40459..6ab8a875 100644
--- a/tests/unit/opera/parser/tosca/test_string.py
+++ b/tests/unit/opera/parser/tosca/test_string.py
@@ -9,9 +9,7 @@ class TestValidate:
     def test_with_string_data(self):
         String.validate(Node("string"))
 
-    @pytest.mark.parametrize(
-        "data", [4,  (), (1, 2, 3), [], ["a", "b"], {}],
-    )
+    @pytest.mark.parametrize("data", [4, (), (1, 2, 3), [], ["a", "b"], {}])
     def test_with_non_string(self, data):
         with pytest.raises(ParseError):
             String.validate(Node(data))
diff --git a/tests/unit/opera/parser/tosca/test_timestamp.py b/tests/unit/opera/parser/tosca/test_timestamp.py
index 6e6d3184..624dd7ce 100644
--- a/tests/unit/opera/parser/tosca/test_timestamp.py
+++ b/tests/unit/opera/parser/tosca/test_timestamp.py
@@ -6,17 +6,17 @@
 
 
 class TestValidate:
-  @pytest.mark.parametrize("timestamp", [
-      "2001-12-15T02:59:43.1Z", "2001-12-14t21:59:43.10-05:00", "2001-12-15 2:59:43.10",
-      "2002-12-14", "2022-04-08T21:59:43.10-06:00",
-  ])
-  def test_valid_timestamp(self, timestamp):
-      Timestamp.validate(Node(timestamp))
+    @pytest.mark.parametrize("timestamp", [
+        "2001-12-15T02:59:43.1Z", "2001-12-14t21:59:43.10-05:00", "2001-12-15 2:59:43.10",
+        "2002-12-14", "2022-04-08T21:59:43.10-06:00",
+    ])
+    def test_valid_timestamp(self, timestamp):
+        Timestamp.validate(Node(timestamp))
 
-  @pytest.mark.parametrize("timestamp", [
-      "", " ", "trash", "1", "-50", "01.01", "2001-12-15T02:59:43.1ZNJ", "20020-311-31",
-      "2001-12-15 50:590?43.10", "-100-12-15 2:59:43.10", "2020-1l0-05-15T00:00:00Z"
-  ])
-  def test_invalid_timestamp(self, timestamp):
-      with pytest.raises(ParseError, match="timestamp"):
-          Timestamp.validate(Node(timestamp))
+    @pytest.mark.parametrize("timestamp", [
+        "", " ", "trash", "1", "-50", "01.01", "2001-12-15T02:59:43.1ZNJ", "20020-311-31",
+        "2001-12-15 50:590?43.10", "-100-12-15 2:59:43.10", "2020-1l0-05-15T00:00:00Z"
+    ])
+    def test_invalid_timestamp(self, timestamp):
+        with pytest.raises(ParseError, match="timestamp"):
+            Timestamp.validate(Node(timestamp))
diff --git a/tests/unit/opera/parser/tosca/test_version.py b/tests/unit/opera/parser/tosca/test_version.py
index 0896c86e..5dd72366 100644
--- a/tests/unit/opera/parser/tosca/test_version.py
+++ b/tests/unit/opera/parser/tosca/test_version.py
@@ -6,17 +6,17 @@
 
 
 class TestValidate:
-  @pytest.mark.parametrize("version", [
-      "0.0", "0.1", "1.1", "123.456", "1.2.0", "1.2.32", "1.2.3.test",
-      "3.4.5.0rev_a", "6.7.8.a-0", "1.3.6.b-123", "1.2.3.4-5",
-  ])
-  def test_valid_version(self, version):
-      Version.validate(Node(version))
+    @pytest.mark.parametrize("version", [
+        "0.0", "0.1", "1.1", "123.456", "1.2.0", "1.2.32", "1.2.3.test",
+        "3.4.5.0rev_a", "6.7.8.a-0", "1.3.6.b-123", "1.2.3.4-5",
+    ])
+    def test_valid_version(self, version):
+        Version.validate(Node(version))
 
-  @pytest.mark.parametrize("version", [
-      "", " ", "garbage", "1", "01.0", "1.02", "1.2.03", "1.2-5", "1-2",
-      "1.2.in-va-lid", "1.2.3-bad", "1.2.3.4-bad",
-  ])
-  def test_invalid_version(self, version):
-      with pytest.raises(ParseError, match="version"):
-          Version.validate(Node(version))
+    @pytest.mark.parametrize("version", [
+        "", " ", "garbage", "1", "01.0", "1.02", "1.2.03", "1.2-5", "1-2",
+        "1.2.in-va-lid", "1.2.3-bad", "1.2.3.4-bad",
+    ])
+    def test_invalid_version(self, version):
+        with pytest.raises(ParseError, match="version"):
+            Version.validate(Node(version))
diff --git a/tests/unit/opera/parser/tosca/test_void.py b/tests/unit/opera/parser/tosca/test_void.py
index af34067f..c340cdf0 100644
--- a/tests/unit/opera/parser/tosca/test_void.py
+++ b/tests/unit/opera/parser/tosca/test_void.py
@@ -1,9 +1,3 @@
-import pytest
-
-from opera.parser.tosca.void import Void
-from opera.parser.utils.location import Location
-
-
 class TestBuild:
     # TODO(@tadeboro): Add tests.
     pass
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_activity_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_activity_definition.py
index 495f2eed..067c9ba1 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_activity_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_activity_definition.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_delegate_workflow(self, yaml_ast):
         ActivityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             delegate:
               workflow: delegate_workflow_name
@@ -14,6 +15,7 @@ def test_delegate_workflow(self, yaml_ast):
 
     def test_delegate_workflow_short(self, yaml_ast):
         ActivityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             delegate: delegate_workflow_name
             """
@@ -21,6 +23,7 @@ def test_delegate_workflow_short(self, yaml_ast):
 
     def test_set_state(self, yaml_ast):
         ActivityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             set_state: new_node_state
             """
@@ -28,6 +31,7 @@ def test_set_state(self, yaml_ast):
 
     def test_call_operation(self, yaml_ast):
         ActivityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             call_operation:
               operation: my.interfaces.scaling.scale_up
@@ -38,6 +42,7 @@ def test_call_operation(self, yaml_ast):
 
     def test_call_operation_short(self, yaml_ast):
         ActivityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             call_operation: my.interfaces.scaling.scale_up
             """
@@ -45,6 +50,7 @@ def test_call_operation_short(self, yaml_ast):
 
     def test_inline_workflow(self, yaml_ast):
         ActivityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             inline:
               workflow: delegate_workflow_name
@@ -55,6 +61,7 @@ def test_inline_workflow(self, yaml_ast):
 
     def test_inline_workflow_short(self, yaml_ast):
         ActivityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             inline: delegate_workflow_name
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_artifact_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_artifact_definition.py
index a20e2b3d..ef51d346 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_artifact_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_artifact_definition.py
@@ -29,6 +29,7 @@ def test_dict_normalization(self):
 class TestParse:
     def test_full(self, yaml_ast):
         ArtifactDefinition.parse(yaml_ast(
+            # language=yaml
             """
             description: My arty desc
             type: my.type
@@ -44,6 +45,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         ArtifactDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: my.type
             file: some/file
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_artifact_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_artifact_type.py
index 1b0bfabd..00262714 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_artifact_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_artifact_type.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         ArtifactType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: artifact_type
             description: My desc
@@ -20,6 +21,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         ArtifactType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: artifact_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_attribute_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_attribute_definition.py
index ebfd27b6..d3259b98 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_attribute_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_attribute_definition.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         AttributeDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: my_type
             description: Some desc
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_capability_assignment.py b/tests/unit/opera/parser/tosca/v_1_3/test_capability_assignment.py
index 00536024..3ed0902d 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_capability_assignment.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_capability_assignment.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         CapabilityAssignment.parse(yaml_ast(
+            # language=yaml
             """
             properties:
               prop: value
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_capability_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_capability_definition.py
index 6784807f..5ead9618 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_capability_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_capability_definition.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         CapabilityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: cap_type_name
             description: Some text
@@ -16,6 +17,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         CapabilityDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: cap_type_name
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_capability_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_capability_type.py
index 0028b9ca..4340dafb 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_capability_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_capability_type.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         CapabilityType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: cap_type
             description: My desc
@@ -23,6 +24,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         CapabilityType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: cap_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_condition_clause_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_condition_clause_definition.py
index 6ac4a18f..a0022068 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_condition_clause_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_condition_clause_definition.py
@@ -7,6 +7,7 @@
 class TestParseValidate:
     def test_valid_clause_direct_assertion(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             my_attribute: [ { equal: 42 } ]
             """
@@ -16,6 +17,7 @@ def test_valid_clause_direct_assertion(self, yaml_ast):
 
     def test_valid_clause_direct_assertion_list(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             my_attribute: [ { min_length: 1 }, { min_length: 11 } ]
             """
@@ -25,6 +27,7 @@ def test_valid_clause_direct_assertion_list(self, yaml_ast):
 
     def test_valid_clause_not(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             not:
               - my_attribute: [{equal: my_value}]
@@ -36,6 +39,7 @@ def test_valid_clause_not(self, yaml_ast):
 
     def test_valid_clause_and(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             and:
               - my_attribute: [{equal: my_value}]
@@ -47,6 +51,7 @@ def test_valid_clause_and(self, yaml_ast):
 
     def test_valid_clause_not_and(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             not:
               - and:
@@ -59,6 +64,7 @@ def test_valid_clause_not_and(self, yaml_ast):
 
     def test_valid_clause_or(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             or:
               - my_attribute: [{equal: my_value}]
@@ -70,6 +76,7 @@ def test_valid_clause_or(self, yaml_ast):
 
     def test_valid_clause_or_not(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             or:
               - not:
@@ -83,6 +90,7 @@ def test_valid_clause_or_not(self, yaml_ast):
 
     def test_valid_clause_or_and_not(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             or:
               - and:
@@ -98,6 +106,7 @@ def test_valid_clause_or_and_not(self, yaml_ast):
 
     def test_valid_clause_nested(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             or:
               - not:
@@ -131,6 +140,7 @@ def test_valid_clause_nested(self, yaml_ast):
 
     def test_invalid_clause_not(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             nott:
               - my_attribute: [{equal: my_value}]
@@ -143,6 +153,7 @@ def test_invalid_clause_not(self, yaml_ast):
 
     def test_invalid_clause_nested(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             or:
               - not:
@@ -176,6 +187,7 @@ def test_invalid_clause_nested(self, yaml_ast):
 
     def test_invalid_clause_assert(self, yaml_ast):
         test_yaml = yaml_ast(
+            # language=yaml
             """
             assert:
               - my_attribute: [{equal: my_value}]
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_constraint_clause.py b/tests/unit/opera/parser/tosca/v_1_3/test_constraint_clause.py
index b4150c80..4711e399 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_constraint_clause.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_constraint_clause.py
@@ -12,6 +12,7 @@ def test_invalid_clause(self, yaml_ast):
         with pytest.raises(ParseError):
             ConstraintClause.validate(yaml_ast("bad_operator: must fail"))
 
+
 class TestParse:
     def test_parse(self, yaml_ast):
         ConstraintClause.parse(yaml_ast("in_range: [ 1, 2 ]"))
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_credential.py b/tests/unit/opera/parser/tosca/v_1_3/test_credential.py
index 32217d61..c089a6e5 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_credential.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_credential.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         Credential.parse(yaml_ast(
+            # language=yaml
             """
             protocol: tcp
             token_type: password
@@ -17,6 +18,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         Credential.parse(yaml_ast(
+            # language=yaml
             """
             token: my_password
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_data_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_data_type.py
index bfe75bc9..b3ed6d64 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_data_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_data_type.py
@@ -23,6 +23,7 @@ def test_updates_dict_data_with_derived_from_key(self):
 class TestParse:
     def test_full(self, yaml_ast):
         DataType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: data_type
             description: My desc
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_event_filter_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_event_filter_definition.py
index 376029cf..57ff2971 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_event_filter_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_event_filter_definition.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         EventFilterDefinition.parse(yaml_ast(
+            # language=yaml
             """
             node: node_type_name
             requirement: requirement_name
@@ -13,6 +14,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         EventFilterDefinition.parse(yaml_ast(
+            # language=yaml
             """
             node: node_template_name
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_group_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_group_definition.py
index 2a15777e..8998a870 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_group_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_group_definition.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         GroupDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: node.type
             description: Text
@@ -18,6 +19,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         GroupDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: group.type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_group_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_group_type.py
index 773210d3..aaf3605e 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_group_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_group_type.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         GroupType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: group_type
             description: My desc
@@ -18,6 +19,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         GroupType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: group_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_import_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_import_definition.py
index bce443f6..6a017cb8 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_import_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_import_definition.py
@@ -22,6 +22,7 @@ def test_failed_normalization(self, data):
 class TestParse:
     def test_full(self, yaml_ast):
         ImportDefinition.parse(yaml_ast(
+            # language=yaml
             """
             file: my/file
             repository: my_repo
@@ -32,6 +33,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         ImportDefinition.parse(yaml_ast(
+            # language=yaml
             """
             file: my/file
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_interface_definition_for_template.py b/tests/unit/opera/parser/tosca/v_1_3/test_interface_definition_for_template.py
index 7c0d6dbf..0e6d47ca 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_interface_definition_for_template.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_interface_definition_for_template.py
@@ -1,11 +1,10 @@
-from opera.parser.tosca.v_1_3.interface_definition_for_template import (
-    InterfaceDefinitionForTemplate,
-)
+from opera.parser.tosca.v_1_3.interface_definition_for_template import InterfaceDefinitionForTemplate
 
 
 class TestParse:
     def test_full(self, yaml_ast):
         InterfaceDefinitionForTemplate.parse(yaml_ast(
+            # language=yaml
             """
             inputs:
               in: put
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_interface_definition_for_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_interface_definition_for_type.py
index 3aad216c..e76b0694 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_interface_definition_for_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_interface_definition_for_type.py
@@ -1,11 +1,10 @@
-from opera.parser.tosca.v_1_3.interface_definition_for_type import (
-    InterfaceDefinitionForType,
-)
+from opera.parser.tosca.v_1_3.interface_definition_for_type import InterfaceDefinitionForType
 
 
 class TestParse:
     def test_full(self, yaml_ast):
         InterfaceDefinitionForType.parse(yaml_ast(
+            # language=yaml
             """
             inputs: {}
             operations: {}
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_interface_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_interface_type.py
index de186284..1be3b9a0 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_interface_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_interface_type.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         InterfaceType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: interface_type
             description: My desc
@@ -20,6 +21,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         InterfaceType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: interface_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_node_filter_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_node_filter_definition.py
index 89d21653..e1a0673b 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_node_filter_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_node_filter_definition.py
@@ -1,11 +1,10 @@
-from opera.parser.tosca.v_1_3.node_filter_definition import (
-    NodeFilterDefinition,
-)
+from opera.parser.tosca.v_1_3.node_filter_definition import NodeFilterDefinition
 
 
 class TestParse:
     def test_full(self, yaml_ast):
         NodeFilterDefinition.parse(yaml_ast(
+            # language=yaml
             """
             properties:
               - num_cpus: { in_range: [ 3, 6 ] }
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_node_template.py b/tests/unit/opera/parser/tosca/v_1_3/test_node_template.py
index bcc740d5..9fabbcb8 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_node_template.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_node_template.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         NodeTemplate.parse(yaml_ast(
+            # language=yaml
             """
             type: node.type
             description: Text
@@ -22,6 +23,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         NodeTemplate.parse(yaml_ast(
+            # language=yaml
             """
             type: node.type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_node_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_node_type.py
index d55081df..f662945b 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_node_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_node_type.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         NodeType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: node_type
             description: My desc
@@ -23,6 +24,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         NodeType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: node_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_notification_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_notification_definition.py
index 8b484ed2..5dc2919c 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_notification_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_notification_definition.py
@@ -1,11 +1,10 @@
-from opera.parser.tosca.v_1_3.notification_definition import (
-    NotificationDefinition,
-)
+from opera.parser.tosca.v_1_3.notification_definition import NotificationDefinition
 
 
 class TestParse:
     def test_full(self, yaml_ast):
         NotificationDefinition.parse(yaml_ast(
+            # language=yaml
             """
             description: Bla bla bla
             implementation: path/to/artifact
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_notification_implementation_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_notification_implementation_definition.py
index 4ee0d7de..7c2ddd40 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_notification_implementation_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_notification_implementation_definition.py
@@ -1,9 +1,7 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.v_1_3.notification_implementation_definition import (
-    NotificationImplementationDefinition,
-)
+from opera.parser.tosca.v_1_3.notification_implementation_definition import NotificationImplementationDefinition
 from opera.parser.yaml.node import Node
 
 
@@ -28,6 +26,7 @@ def test_dict_normalization(self):
 class TestParse:
     def test_full(self, yaml_ast):
         NotificationImplementationDefinition.parse(yaml_ast(
+            # language=yaml
             """
             primary: first
             dependencies:
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_operation_definition_for_template.py b/tests/unit/opera/parser/tosca/v_1_3/test_operation_definition_for_template.py
index d2e45e6e..140d820f 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_operation_definition_for_template.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_operation_definition_for_template.py
@@ -1,9 +1,7 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.v_1_3.operation_definition_for_template import (
-    OperationDefinitionForTemplate,
-)
+from opera.parser.tosca.v_1_3.operation_definition_for_template import OperationDefinitionForTemplate
 from opera.parser.yaml.node import Node
 
 
@@ -28,6 +26,7 @@ def test_dict_normalization(self):
 class TestParse:
     def test_full(self, yaml_ast):
         OperationDefinitionForTemplate.parse(yaml_ast(
+            # language=yaml
             """
             description: Even more text
             implementation: path/to/artifact
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_operation_definition_for_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_operation_definition_for_type.py
index eb65bd68..e3412341 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_operation_definition_for_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_operation_definition_for_type.py
@@ -1,9 +1,7 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.v_1_3.operation_definition_for_type import (
-    OperationDefinitionForType,
-)
+from opera.parser.tosca.v_1_3.operation_definition_for_type import OperationDefinitionForType
 from opera.parser.yaml.node import Node
 
 
@@ -28,6 +26,7 @@ def test_dict_normalization(self):
 class TestParse:
     def test_full(self, yaml_ast):
         OperationDefinitionForType.parse(yaml_ast(
+            # language=yaml
             """
             description: Some description
             implementation: bla
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_operation_host.py b/tests/unit/opera/parser/tosca/v_1_3/test_operation_host.py
index fc2c8d3b..7b97d440 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_operation_host.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_operation_host.py
@@ -7,15 +7,13 @@
 
 class TestValidate:
     @pytest.mark.parametrize(
-        "version", ["SELF", "HOST", "SOURCE", "TARGET", "ORCHESTRATOR"],
+        "version", ["SELF", "HOST", "SOURCE", "TARGET", "ORCHESTRATOR"]
     )
     def test_valid_tosca_versions(self, version):
         OperationHost.validate(Node(version))
 
     @pytest.mark.parametrize(
-        "version", [
-            "", "  ", "a", "tosca_simple_yaml_1_3", 123, "abc", {}, [],
-        ],
+        "version", ["", "  ", "a", "tosca_simple_yaml_1_3", 123, "abc", {}, []]
     )
     def test_invalid_tosca_versions(self, version):
         with pytest.raises(ParseError):
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_operation_implementation_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_operation_implementation_definition.py
index 5ce4c394..57bb5e95 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_operation_implementation_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_operation_implementation_definition.py
@@ -1,9 +1,7 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.v_1_3.operation_implementation_definition import (
-    OperationImplementationDefinition,
-)
+from opera.parser.tosca.v_1_3.operation_implementation_definition import OperationImplementationDefinition
 from opera.parser.yaml.node import Node
 
 
@@ -28,6 +26,7 @@ def test_dict_normalization(self):
 class TestParse:
     def test_full(self, yaml_ast):
         OperationImplementationDefinition.parse(yaml_ast(
+            # language=yaml
             """
             primary: artifact
             dependencies:
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_parameter_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_parameter_definition.py
index c22b03ad..495c11b8 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_parameter_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_parameter_definition.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         ParameterDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: data_type_name
             description: My text
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_policy_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_policy_definition.py
index 28cc89e0..cce8d53a 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_policy_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_policy_definition.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         PolicyDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: policy.type
             description: Some muttering
@@ -25,6 +26,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         PolicyDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: policy.type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_policy_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_policy_type.py
index 3d384fd9..60c67966 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_policy_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_policy_type.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         PolicyType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: policy_type
             description: My desc
@@ -46,6 +47,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         PolicyType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: policy_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_property_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_property_definition.py
index dfc3f949..14b33f15 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_property_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_property_definition.py
@@ -1,11 +1,10 @@
-import pytest
-
 from opera.parser.tosca.v_1_3.property_definition import PropertyDefinition
 
 
 class TestParse:
     def test_full(self, yaml_ast):
         PropertyDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: map
             description: My description
@@ -24,6 +23,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         PropertyDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: map
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_range.py b/tests/unit/opera/parser/tosca/v_1_3/test_range.py
index 21ce7866..cae50d51 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_range.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_range.py
@@ -4,23 +4,20 @@
 
 from opera.error import ParseError
 from opera.parser.tosca.v_1_3.range import Range
-from opera.parser.yaml.node import Node
 
 
 class TestValidate:
-    @pytest.mark.parametrize("data", [
-        "[1, 2]", "[3, UNBOUNDED]", "- 3\n- 6",
-    ])
+    @pytest.mark.parametrize("data", ["[1, 2]", "[3, UNBOUNDED]", "- 3\n- 6"])
     def test_with_valid_data(self, data, yaml_ast):
         Range.validate(yaml_ast(data))
 
     @pytest.mark.parametrize("data", [
-        "abc", "4," "{}", "3.4", "false", "null",         # Invalid types
-        "[]", "[1]", "[1, 2, 3]", "[1, 2, 3, 4]",         # Invalid cardinality
+        "abc", "4", "{}", "3.4", "false", "null",  # Invalid types
+        "[]", "[1]", "[1, 2, 3]", "[1, 2, 3, 4]",  # Invalid cardinality
         "[a, 1]", "[2.3, 1]", "[false, 1]", "[null, 1]",  # Invalid lo type
         "[0, 1.3]", "[0, true]", "[0, null]", "[0, {}]",  # Invalid hi type
-        "[0, a]", "[0, \"\"]", "[0, BAD]",                # Invalid hi string
-        "[5, 2]", "[-3, -6]", "[4, -3]",                  # lo > hi
+        "[0, a]", "[0, \"\"]", "[0, BAD]",  # Invalid hi string
+        "[5, 2]", "[-3, -6]", "[4, -3]",  # lo > hi
     ])
     def test_invalid_data(self, data, yaml_ast):
         with pytest.raises(ParseError):
@@ -28,9 +25,9 @@ def test_invalid_data(self, data, yaml_ast):
 
 
 class TestBuild:
-    @pytest.mark.parametrize("input,output", [
+    @pytest.mark.parametrize("input_string,output", [
         ("[1, 2]", (1, 2)), ("[-4, 5]", (-4, 5)),
         ("[0, UNBOUNDED]", (0, math.inf)),
     ])
-    def test_construction(self, input, output, yaml_ast):
-        assert Range.build(yaml_ast(input)).data == output
+    def test_construction(self, input_string, output, yaml_ast):
+        assert Range.build(yaml_ast(input_string)).data == output
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_relationship_template.py b/tests/unit/opera/parser/tosca/v_1_3/test_relationship_template.py
index 7560359e..ab411232 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_relationship_template.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_relationship_template.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         RelationshipTemplate.parse(yaml_ast(
+            # language=yaml
             """
             type: rel.type
             description: Some muttering
@@ -22,6 +23,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         RelationshipTemplate.parse(yaml_ast(
+            # language=yaml
             """
             type: rel.type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_relationship_type.py b/tests/unit/opera/parser/tosca/v_1_3/test_relationship_type.py
index a58faebf..6f28bbd5 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_relationship_type.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_relationship_type.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         RelationshipType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: relationship_type
             description: My desc
@@ -19,6 +20,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         RelationshipType.parse(yaml_ast(
+            # language=yaml
             """
             derived_from: relationship_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_repository_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_repository_definition.py
index 020281f5..eae398bb 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_repository_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_repository_definition.py
@@ -1,9 +1,8 @@
 import pytest
 
-from opera.parser.yaml.node import Node
-
 from opera.error import ParseError
 from opera.parser.tosca.v_1_3.repository_definition import RepositoryDefinition
+from opera.parser.yaml.node import Node
 
 
 class TestNormalize:
@@ -23,6 +22,7 @@ def test_failed_normalization(self, data):
 class TestParse:
     def test_full(self, yaml_ast):
         RepositoryDefinition.parse(yaml_ast(
+            # language=yaml
             """
             description: My description
             url: https://repo.name
@@ -33,6 +33,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         RepositoryDefinition.parse(yaml_ast(
+            # language=yaml
             """
             url: https://repo.name
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_requirement_assignment.py b/tests/unit/opera/parser/tosca/v_1_3/test_requirement_assignment.py
index 9326b9f7..20f76dfa 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_requirement_assignment.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_requirement_assignment.py
@@ -7,7 +7,6 @@
 from opera.parser.yaml.node import Node
 
 
-
 class TestNormalize:
     @pytest.mark.parametrize("data", [1, 2.3, True, (), []])
     def test_invalid_data(self, data):
@@ -29,6 +28,7 @@ def test_dict_normalization(self):
 class TestParse:
     def test_full(self, yaml_ast):
         RequirementAssignment.parse(yaml_ast(
+            # language=yaml
             """
             capability: my_cap
             node: some_node_template
@@ -40,6 +40,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         RequirementAssignment.parse(yaml_ast(
+            # language=yaml
             """
             some_node_template
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_requirement_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_requirement_definition.py
index 7679903e..336f9bc4 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_requirement_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_requirement_definition.py
@@ -1,9 +1,7 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.v_1_3.requirement_definition import (
-    RequirementDefinition,
-)
+from opera.parser.tosca.v_1_3.requirement_definition import RequirementDefinition
 from opera.parser.yaml.node import Node
 
 
@@ -28,6 +26,7 @@ def test_dict_normalization(self):
 class TestParse:
     def test_full(self, yaml_ast):
         RequirementDefinition.parse(yaml_ast(
+            # language=yaml
             """
             capability: my_cap_type
             node: my_node_type
@@ -38,6 +37,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         RequirementDefinition.parse(yaml_ast(
+            # language=yaml
             """
             capability: my_cap_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_schema_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_schema_definition.py
index 8640377e..6f0baa99 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_schema_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_schema_definition.py
@@ -1,11 +1,10 @@
-import pytest
-
 from opera.parser.tosca.v_1_3.schema_definition import SchemaDefinition
 
 
 class TestParse:
     def test_full(self, yaml_ast):
         SchemaDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: my_type
             description: My description
@@ -15,6 +14,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         SchemaDefinition.parse(yaml_ast(
+            # language=yaml
             """
             type: my_type
             """
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_service_template.py b/tests/unit/opera/parser/tosca/v_1_3/test_service_template.py
index 9e1fb999..62a46cbf 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_service_template.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_service_template.py
@@ -10,9 +10,7 @@ def test_noop_for_dicts_with_no_dsl_definitions(self):
         assert ServiceTemplate.normalize(Node({})).bare == {}
 
     def test_dsl_definitions_removal(self):
-        assert ServiceTemplate.normalize(Node({
-            Node("dsl_definitions"): "data",
-        })).bare == {}
+        assert ServiceTemplate.normalize(Node({Node("dsl_definitions"): "data"})).bare == {}
 
     @pytest.mark.parametrize("data", [123, 1.4, []])
     def test_failure_with_non_dict_data(self, data):
@@ -22,7 +20,8 @@ def test_failure_with_non_dict_data(self, data):
 
 class TestParse:
     def test_full(self, yaml_ast, tmp_path):
-        ServiceTemplate.parse(yaml_ast(
+        ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             namespace: some.namespace
@@ -51,7 +50,8 @@ def test_full(self, yaml_ast, tmp_path):
         ), tmp_path, tmp_path, set())
 
     def test_minimal(self, yaml_ast, tmp_path):
-        ServiceTemplate.parse(yaml_ast(
+        ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             """
@@ -60,7 +60,8 @@ def test_minimal(self, yaml_ast, tmp_path):
 
 class TestMerge:
     def test_valid_section_merge(self, yaml_ast, tmp_path):
-        template = ServiceTemplate.parse(yaml_ast(
+        template = ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -68,7 +69,8 @@ def test_valid_section_merge(self, yaml_ast, tmp_path):
                 derived_from: a
             """
         ), tmp_path, tmp_path, set())[0]
-        template.merge(ServiceTemplate.parse(yaml_ast(
+        template.merge(ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -82,7 +84,7 @@ def test_valid_section_merge(self, yaml_ast, tmp_path):
         assert template.node_types["type_b"].data["derived_from"].data == "b"
 
     def test_valid_merge(self, yaml_ast, tmp_path):
-        template = ServiceTemplate.parse(yaml_ast(
+        template = ServiceTemplate.parse_service_template(yaml_ast(
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             data_types:
@@ -90,7 +92,8 @@ def test_valid_merge(self, yaml_ast, tmp_path):
                 derived_from: a
             """
         ), tmp_path, tmp_path, set())[0]
-        template.merge(ServiceTemplate.parse(yaml_ast(
+        template.merge(ServiceTemplate.parse_service_template(yaml_ast(
+            # language=yaml
             """
             tosca_definitions_version: tosca_simple_yaml_1_3
             node_types:
@@ -104,14 +107,16 @@ def test_valid_merge(self, yaml_ast, tmp_path):
 
     def test_duplicates(self, yaml_ast, tmp_path):
         with pytest.raises(ParseError, match="type_a"):
-            ServiceTemplate.parse(yaml_ast(
+            ServiceTemplate.parse_service_template(yaml_ast(
+                # language=yaml
                 """
                 tosca_definitions_version: tosca_simple_yaml_1_3
                 node_types:
                   type_a:
                     derived_from: a
                 """
-            ), tmp_path, tmp_path, set())[0].merge(ServiceTemplate.parse(yaml_ast(
+            ), tmp_path, tmp_path, set())[0].merge(ServiceTemplate.parse_service_template(yaml_ast(
+                # language=yaml
                 """
                 tosca_definitions_version: tosca_simple_yaml_1_3
                 node_types:
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_status.py b/tests/unit/opera/parser/tosca/v_1_3/test_status.py
index b547018a..007c060a 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_status.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_status.py
@@ -6,15 +6,11 @@
 
 
 class TestValidate:
-    @pytest.mark.parametrize(
-        "status", ["supported", "unsupported", "experimental", "deprecated"],
-    )
+    @pytest.mark.parametrize("status", ["supported", "unsupported", "experimental", "deprecated"])
     def test_valid_status(self, status):
         Status.validate(Node(status))
 
-    @pytest.mark.parametrize(
-        "status", ["some", "random", "stuff", 1, 2, [], {}, (), 1.2, False],
-    )
+    @pytest.mark.parametrize("status", ["some", "random", "stuff", 1, 2, [], {}, (), 1.2, False])
     def test_invalid_status(self, status):
         with pytest.raises(ParseError):
             Status.validate(Node(status))
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_time_interval.py b/tests/unit/opera/parser/tosca/v_1_3/test_time_interval.py
index 39c358f3..371dc8ec 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_time_interval.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_time_interval.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_minimal(self, yaml_ast):
         TimeInterval.parse(yaml_ast(
+            # language=yaml
             """
             start_time: 2020-04-08T21:59:43.10-06:00
             end_time: 2022-04-08T21:59:43.10-06:00
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_topology_template.py b/tests/unit/opera/parser/tosca/v_1_3/test_topology_template.py
index 9423610d..19bd14f5 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_topology_template.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_topology_template.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         TopologyTemplate.parse(yaml_ast(
+            # language=yaml
             """
             description: Topology description
             inputs:
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_tosca_definitions_version.py b/tests/unit/opera/parser/tosca/v_1_3/test_tosca_definitions_version.py
index e76771d7..1d8158ba 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_tosca_definitions_version.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_tosca_definitions_version.py
@@ -1,9 +1,7 @@
 import pytest
 
 from opera.error import ParseError
-from opera.parser.tosca.v_1_3.tosca_definitions_version import (
-    ToscaDefinitionsVersion,
-)
+from opera.parser.tosca.v_1_3.tosca_definitions_version import ToscaDefinitionsVersion
 from opera.parser.yaml.node import Node
 
 
diff --git a/tests/unit/opera/parser/tosca/v_1_3/test_trigger_definition.py b/tests/unit/opera/parser/tosca/v_1_3/test_trigger_definition.py
index c0422674..a72d630c 100644
--- a/tests/unit/opera/parser/tosca/v_1_3/test_trigger_definition.py
+++ b/tests/unit/opera/parser/tosca/v_1_3/test_trigger_definition.py
@@ -4,6 +4,7 @@
 class TestParse:
     def test_full(self, yaml_ast):
         TriggerDefinition.parse(yaml_ast(
+            # language=yaml
             """
             description: A trigger
             event: trigger
@@ -31,6 +32,7 @@ def test_full(self, yaml_ast):
 
     def test_minimal(self, yaml_ast):
         TriggerDefinition.parse(yaml_ast(
+            # language=yaml
             """
             event: trigger
             action:
diff --git a/tests/unit/opera/parser/utils/test_location.py b/tests/unit/opera/parser/utils/test_location.py
index 3eb7cc4e..091f5031 100644
--- a/tests/unit/opera/parser/utils/test_location.py
+++ b/tests/unit/opera/parser/utils/test_location.py
@@ -1,5 +1,6 @@
 from opera.parser.utils.location import Location
 
+
 class TestStr:
     def test_str(self):
         assert str(Location("stream", 1, 2)) == "stream:1:2"
diff --git a/tests/unit/opera/parser/yaml/test_constructor.py b/tests/unit/opera/parser/yaml/test_constructor.py
index ee888928..b0c3fc5b 100644
--- a/tests/unit/opera/parser/yaml/test_constructor.py
+++ b/tests/unit/opera/parser/yaml/test_constructor.py
@@ -1,9 +1,9 @@
 import math
 
 import pytest
+from yaml.constructor import ConstructorError
 from yaml.error import Mark
 from yaml.nodes import MappingNode, ScalarNode, SequenceNode
-from yaml.constructor import ConstructorError
 
 from opera.parser.yaml.constructor import Constructor
 
@@ -154,4 +154,5 @@ def test_construct_map_duplicate(self):
         ]
         node = MappingNode("tag:yaml.org,2002:map", children, start_mark=mark)
         with pytest.raises(ConstructorError):
-            res, = Constructor("map").construct_yaml_map(node)
+            generator = Constructor("map").construct_yaml_map(node)
+            list(generator)
diff --git a/tests/unit/opera/parser/yaml/test_loader.py b/tests/unit/opera/parser/yaml/test_loader.py
index 17da1d1c..bb98f925 100644
--- a/tests/unit/opera/parser/yaml/test_loader.py
+++ b/tests/unit/opera/parser/yaml/test_loader.py
@@ -2,7 +2,6 @@
 import textwrap
 
 import pytest
-from yaml.error import YAMLError
 
 from opera.parser import yaml
 
@@ -17,12 +16,14 @@ def ystr(string):
     ("1.2", 1.2),
     ("NULL", None),
     (
+        # language=yaml
         ystr("""
              test: map
              """),
         dict(test="map"),
     ),
     (
+        # language=yaml
         ystr("""
              - list
              - 1
@@ -33,6 +34,7 @@ def ystr(string):
         ["list", 1, " is", math.inf, "here"],
     ),
     (
+        # language=yaml
         ystr("""
              d:
                - with
@@ -54,6 +56,6 @@ def ystr(string):
 
 
 class TestLoad:
-    @pytest.mark.parametrize("input,output", VALID_TEST_CASES)
-    def test_load_valid_yaml(self, input, output):
-        assert yaml.load(input, "test").bare == output
+    @pytest.mark.parametrize("input_string,output", VALID_TEST_CASES)
+    def test_load_valid_yaml(self, input_string, output):
+        assert yaml.load(input_string, "test").bare == output
diff --git a/tests/unit/opera/parser/yaml/test_node.py b/tests/unit/opera/parser/yaml/test_node.py
index bf32c192..298e91f1 100644
--- a/tests/unit/opera/parser/yaml/test_node.py
+++ b/tests/unit/opera/parser/yaml/test_node.py
@@ -31,9 +31,7 @@ def test_bare_map(self):
         assert Node({Node(1): Node("a")}).bare == {1: "a"}
 
     def test_base_nested(self):
-        node = Node({
-            Node(1): Node([Node(1), Node("a")]),
-        })
+        node = Node({Node(1): Node([Node(1), Node("a")])})
 
         assert node.bare == {1: [1, "a"]}