utils.fact_sheet
Parent class for all fact sheet types. Contains all methods that are identical between all fact sheet types.
The following fact sheet attributes loaded by default, plus all fields specific to the fact sheet type:
id
name
displayName
description
rev
level
type
qualitySeal
lxState
naFields
status
createdAt
updatedAt
tags (simplified structure)
subscriptions (simplified structure)
documents (simplified structure)
permittedWriteACL{id name} (only if ACL feature is enabled)
permittedReadACL{id name} (only if ACL feature is enabled)
Only used internally. To instantiate a fact sheet, use the respective child class, e.g. Application().
Follows the relation specified by key
from the current fact sheet and returns a list of all related fact sheets.
key
can either be the key of a relation, e.g. relApplicationToProcess
, or a fact sheet type, e.g. Process
.
In the latter case, the relation key is derived from the relation model. In case of ambiguous relation keys, a
warning is logged.
This function is usually never called directly. It's rather recommended to directly call fs.key, e.g.
app.processes()
or app.relApplicationToProcess()
.
Avoids the usage of eval(fs_type)(id) if you want to instantiate fact sheets based on a dynamic type.
Returns a list of all fact sheet types, as strings (not Python classes).
To get the corresponding classes, use get_fs_class
.
depending on the usage, this method either loads a single fact sheet or all fact sheets of a certain type.
fs_type
: The fact sheet type to be loaded.
fs_id
: The id of the fact sheet to be loaded (if any, otherwise None
).
filter_list
: List of facet filters. See FactSheet.filter() for documentation.
Returns either the fact sheet (as json response, unprocessed) or the list of fact sheets (equally unprocessed).
All responses are harmonized to turn them into a more useful and "pythonic" data structure.
Careful when using this: It returns a list of all fact sheets in the workspace, so this can be huge.
Can be used to remove all fact sheets from a new workspace to start with a clean and empty workspace:
for fs in FactSheet.all():
fs.archive()
Returns a list of all fact sheets that match the facet filters.
Examples:
# Filter by lifecycle range
apps = Application.filter(
[
{
"facetKey": "lifecycle",
"operator": "OR",
"keys": [
"active"
],
"dateFilter": {
"type": "RANGE",
"from": "2023-01-01",
"to": "2023-12-31"
}
}
]
)
# Applications that have a subscription (NOR + missing = "any subscription")
apps = Application.filter(
[
{
"facetKey": "Subscriptions",
"operator": "NOR",
"keys": [
"__missing__"
]
}
]
)
# Filter by relation including filter on relation field
apps = Application.filter(
[
{
"facetKey": "relApplicationToUserGroup",
"operator": "OR",
"keys": [
TEST_USERGROUP
],
"relationFieldsFilter": [
{
"fieldName": "usageType",
"values": [
"user"
]
}
],
"relationFieldsFilterOperator": "INCLUSIVE",
# INCLUSIVE:
# Only the matches of the applied relation field filters are kept in the response.
#
# EXCLUSIVE:
# The matches of the applied relation field filters are removed from the response.
}
]
)
# Filter by relation including transitively (parent/child) related fact sheets
apps = Application.filter(
[
{
"facetKey": "relApplicationToUserGroup",
"operator": "OR",
"keys": [
TEST_USERGROUP
]
}
]
)
# Filter by relation excluding transitively (parent/child) related fact sheets
apps = Application.filter(
[
{
"facetKey": "relApplicationToUserGroup",
"operator": "OR",
"keys": [
TEST_USERGROUP
],
"excludeTransitiveRelations": True
}
]
)
# Filter by relation=n/a
apps = Application.filter(
# Facet filter for "FactSheetTypes = Application" is added automatically, doesn't need to be added here
[
{
"facetKey": "relApplicationToUserGroup",
"operator": "OR",
"keys": [
"__missing__"
],
"relationFieldsFilter": [],
"relationFieldsFilterOperator": "INCLUSIVE",
}
]
)
# Advanced filter: Apps with relations to IT Components that are EoL today
apps = Application.filter(
[
{
"facetKey": "relApplicationToITComponent",
"operator": "OR",
"keys": [],
"relationFieldsFilterOperator": "INCLUSIVE",
"relationFieldsFilter": [],
"subFilter": {
"facetFilters": [
{
"facetKey": "FactSheetTypes",
"operator": "OR",
"keys": [
"ITComponent"
]
},
{
"facetKey": "lifecycle",
"operator": "OR",
"keys": [
"endOfLife"
],
"dateFilter": {
"from": "2023-02-22",
"to": "2023-02-22",
"type": "TODAY",
}
}
],
}
}
]
)
# Advanced filter: Providers with two-step indirect relation to one specific Application (via ITComponents)
providers = Provider.filter(
[
{
"facetKey": "relProviderToITComponent",
"operator": "OR",
"keys": [],
"excludeTransitiveRelations": True,
"subFilter": {
"facetFilters": [
{
"facetKey": "FactSheetTypes",
"operator": "OR",
"keys": [
"ITComponent"
]
},
{
"facetKey": "relITComponentToApplication",
"operator": "OR",
"keys": [
TEST_APP
],
"excludeTransitiveRelations": True
},
],
}
}
]
)
# Date filter for lifecycle "active" in a specific year
apps = Application.filter(
[
{
"facetKey": "lifecycle",
"operator": "OR",
"keys": [
"active"
# Use value "__any__" to filter for "any" lifecycle
],
"dateFilter": {
"from": str(datetime.datetime.today().year) + "-01-01",
"to": str(datetime.datetime.today().year) + "-12-31",
"type": "RANGE",
# Alternative values:
# "POINT",
# "TODAY",
# "END_OF_MONTH",
# "END_OF_YEAR",
# "RANGE",
# "RANGE_STARTS",
# "RANGE_ENDS",
}
}
]
)
# Applications on hierarchy level 1
apps = Application.filter(
[
{
"facetKey": "hierarchyLevel",
"operator": "OR",
"keys": [
"1"
]
}
]
)
# Filter by quality state
apps = Application.filter(
[
{
"facetKey": "lxState",
"operator": "OR",
"keys": [
"BROKEN_QUALITY_SEAL",
# other values: "DRAFT", "REJECTED", "APPROVED"
]
}
]
)
# Filter by archived state
apps = Application.filter(
[
{
"facetKey": "TrashBin",
"operator": "OR",
"keys": [
"archived",
]
}
]
)
# Filter by tags
apps = Application.filter(
[
{
"facetKey": LeanIXClient().get_tag_group_id("Application Type"),
"operator": "OR",
"keys": [
LeanIXClient().get_tag_id(tag_group="Application Type", tag="Web-based"),
# Use value "__missing__" to get all fact sheets that don't have a tag in this group.
]
}
]
)
# Filter by tags in "Other Tags" group
apps = Application.filter(
[
{
"facetKey": LeanIXClient().get_tag_group_id("Other tags"),
"operator": "OR",
"keys": [
LeanIXClient().get_tag_id(tag_group="Other tags", tag="Holding"),
# Use value "__missing__" to get all fact sheets that don't have a tag in this group.
]
}
]
)
# Filter by tags=n/a
apps = Application.filter(
[
{
"facetKey": LeanIXClient().get_tag_group_id("Application Type"),
"operator": "OR",
"keys": [
"__missing__" # (filters for n/a)
]
}
]
)
# Filter by subscriptions ("me" filter + role)
apps = Application.filter(
[
{
"facetKey": "Subscriptions",
"operator": "OR",
"keys": [
"__me__"
# "__missing__" (filters for n/a)
],
"subscriptionFilter": {
"type": "RESPONSIBLE",
"roleId": LeanIXClient().get_role_id("Application Owner")
}
}
]
)
# Filter by subscription e-mail
apps = Application.filter(
[
{
"facetKey": "Subscriptions",
"operator": "OR",
"keys": [
LeanIXUser.find_by_email("john.doe@example.com")["id"]
# "__missing__" (filters for n/a)
]
}
]
)
# Filter by subscription=n/a
apps = Application.filter(
[
{
"facetKey": "Subscriptions",
"operator": "OR",
"keys": [
"__missing__" # (filters for n/a)
]
}
]
)
# Filter by "data quality" filter set
apps = Application.filter(
[
{
"facetKey": "DataQuality",
"operator": "OR",
"keys": [
"_noResponsible_"
# Other values: "_qualitySealBroken_", "_noDescription_", "_noLifecycle_"
]
}
]
)
# Filter by fact sheet property (single select)
apps = Application.filter(
[
{
"facetKey": "functionalSuitability",
"operator": "OR",
"keys": [
"appropriate"
# other values: "unreasonable", "insufficient", "perfect"
# Use the value "__missing__" to filter for "n/a"
]
}
]
)
Checks if a fact sheet type has already been loaded to the cache. If not, it loads all fact sheets of this type via cls.load() and instantiates them, which stores them in the cache.
fs_type
: The fact sheet type, such as application.Application
. If None
: Load all fact sheets of all types.
Returns a list of all instances of the given fact sheet type.
force
: If set to True
, reload all fact sheets from LeanIX, even if this fact sheet type has already been
loaded.
Returns a list of all parent fact sheets of this fact sheet. This list usually contains only one element.
Almost identical to the standard Python collection 'get' method, except that it also returns the default if 'key' is in self and self[key] is None. Usually, get() would return None, which is somewhat impractical if you would like to chain get() requests with a default value of {} for simplicity.
Creates a new fact sheet. name
is mandatory, description
, tags
and lifecycle
are optional.
tags
example: {"TagGroup": ["Tag 1", "Tag 2"...]}
lifecycle
example: {"plan": "2020-01-31", "phaseIn": "2021-01-31", "active": "2022-01-31",
"phaseOut": "2023-01-31", "endOfLife": "2024-01-31"}
Please ignore the trailing underscore "_", the method is called archive(...)
.
This documentation entry is just there to inform you that you can call archive
on both the FactSheet class
but also on an instance.
Examples:
FactSheet.archive("fac7f0a6-88be-49fd-8935-1fde3edd335d", "Fact sheet was redundant")
Application("My test application").archive("Fact sheet was redundant")
Please ignore the trailing underscore "_", the method is called restore(...)
.
This documentation entry is just there to inform you that you can call restore
on both the FactSheet class
but also on an instance.
Examples:
FactSheet.restore("fac7f0a6-88be-49fd-8935-1fde3edd335d", "Fact sheet was archived mistakenly")
Application("My test application").restore("Fact sheet was archived mistakenly")
This documentation entry is just there to inform you that you can call archive
on both the FactSheet class
but also on an instance.
Examples:
FactSheet.archive("fac7f0a6-88be-49fd-8935-1fde3edd335d", "Fact sheet was redundant")
Application("My test application").archive("Fact sheet was redundant")
This documentation entry is just there to inform you that you can call restore
on both the FactSheet class
but also on an instance.
Examples:
FactSheet.restore("fac7f0a6-88be-49fd-8935-1fde3edd335d", "Fact sheet was archived mistakenly")
Application("My test application").restore("Fact sheet was archived mistakenly")
Checks if the said fact sheet exists, and if so, archives it.
Can be used to clean up the environment before running automated test cases.
Checks if the fact sheet has specific tags or tags in specific tag groups.
If only the parameter "tag=" is set, it returns True if the fact sheet has a tag named tag
in any tag group.
If only "tag_group=" is given, it returns True if the fact sheet has at least one tag in the tag group tag_group
.
If "tag=" and "tag_group=" is set, it returns True if the fact sheet has a tag named tag
in the tag group tag_group
.
Example:
app = Application("My Application")
if app.has_tag(tag="Global"):
# Application has "Global" tag in any tag group
if app.has_tag(tag="Global", tag_group="Application Type"):
# Application has "Global" tag in tag group "Application Type"
if app.has_tag(tag_group="Application Type"):
# Application has at least one tag in tag group "Application Type"
Subscribes a user to a fact sheet.
user_id_or_email
is the user ID or e-mail address of the user to be subscribed.
subscription_type
is the role type to subscribe. Default: "RESPONSIBLE"
role_name
is The role name to be subscribed. Default: None
.
comment
is the comment to be added to the subscription. Default: Empty.
If a subscription of this user in this role_name
already exists, the comment is updated.
Returns the ["data"]
part of the API response object.
Updates the comment of an existing subscription given by the user, subscription_type and role_name.
Change the subscription type of existing subscriptions, e.g. from OBSERVER to RESPONSIBLE.
Warning: LeanIX will allow you to even change the subscription type if some of the related subscription
roles are not configured for the target subscription type.
If you want to avoid an inconsistent state, make sure that all relevant roles support the target subscription
types, e.g. via setting their subscription type to "All" first.
This method automatically checks if the target subscription type is valid for all relevant roles. To override
this check, use force=True.
Example:
app = Application("My Application")
app.change_subscription_type("user@example.com", "RESPONSIBLE")
Deletes a subscription.
Needs at least one of the following parameters to identify the subscription: subscription_id
,
subscription_user_id
, user_email
.
In case you want to delete only an individual role within the subscription and not the entire subscription
for this user, you can use the optional parameters role
and subscription_type
to specify the role you want
to delete. If you do this, please note: If you are deleting an individual role from - say - a RESPONSIBLE
subscription, and it's the last role in that subscription, you will end up with an empty RESPONSIBLE
subscription, which is maybe not what you expect.
To delete the entire subscription when the last role was deleted, set
options={"delete_entire_subscription_if_last_role_is_removed": True}
Creates a relation to another fact sheet. target
is a fact sheet, attributes
are the attributes
on the relation. If there are multiple relation types between the two fact sheet types, you need to
specify rel_type
, e.g. relApplicationToUserGroup
. All valid relation types can be found in your
auto-generated utils/ws_[workspace_name]/fact_sheet_types.py
.
If you want to use line breaks in multiline fields, e.g. for 'description', you need to use the literal
string r'
' or '\n' instead of newline strings '
'.
Returns False
if the relation already exists, so that you don't need to .reload() after calling.
Example:
app = Application("My Application")
ug = UserGroup("My User Group")
attributes = {
"usageType": "owner",
"numberOfUsers": 101,
"functionalSuitability": "insufficient",
"description": r"This is a description.\nAnd this is line 2 of the description.",
"activeFrom": "2022-07-20",
"activeUntil": "2022-07-21"
}
app.create_relation(ug, attributes)
Example including relation type:
app = Application("My Application")
provider = Provider("My Provider")
attributes = {}
app.create_relation(ug, attributes, "relToRequires")
Deletes the relation between this fact sheet and the target
.
If there are multiple relation types between the two fact sheet types, you need to
specify rel_type
, e.g. relApplicationToUserGroup
. All valid relation types can be found in your
auto-generated utils/ws_[workspace_name]/fact_sheet_types.py
.
Example:
app = Application("My Application")
ug = UserGroup("My User Group")
app.delete_relation(ug)
Updates the relation between this fact sheet and the target
.
If there are multiple relation types between the two fact sheet types, you need to
specify rel_type
, e.g. relApplicationToUserGroup
. All valid relation types can be found in your
auto-generated utils/ws_[workspace_name]/fact_sheet_types.py
.
Note that if you omit any already existing attributes in the attributes
parameter, their values will not
be changed.
Example:
app = Application("My Application")
ug = UserGroup("My User Group")
attributes = {
"numberOfUsers": 201,
"description": "This is a new description."
}
# only updates the attributes "numberOfUsers" and "description".
app.update_relation(ug)
Replaces the target of an existing relation to the current fact sheet target
to the new fact sheet new_target
while keeping all of its relation attributes.
Returns the relation between this fact sheet and the target
. This is a convenience function to
access the attributes on the relation in an easy way.
If there are multiple relation types between the two fact sheet types, you need to
specify rel_type
, e.g. relApplicationToUserGroup
. All valid relation types can be found in your
auto-generated utils/ws_[workspace_name]/fact_sheet_types.py
. If you do not specify a relation type,
it will return the first relation that it finds. It will, however, not scan relToRequires and relToRequiredBy.
Instead of passing a FactSheet instance as target, you can pass a target_id and rel_type.
Example:
app = Application("My Application")
ug = UserGroup("My User Group")
rel = app.get_relation(ug)
print(rel["description"])
print(rel["activeFrom"])
Returns the first relation of this fact sheet to any target fact sheet with fact sheet type = fs_type
or
with relation type = rel_type
where the relation attribute given by the key in the match
dict matches the
value given by match[key] (or any of the values in match[key], if match[key] is a list).
If no relations are found and the fallback parameter is provided, it searches again, and uses the "fallback"
parameter as match.
Example - finding the owning user group of an application:
app.get_matching_relation("UserGroup", {"usageType": "owner"})
See get_matching_relation(), but returns all relations instead of just the first one.
Adds a resource to a fact sheet. resourceType
needs to be a valid resource type as defined in LeanIX.
Example:
app.add_resource("My resource", "https://example.com/resource.html", "documentation", "My description")
Deletes the resource with the given resource_id
.
Example:
# Delete all resources from a fact sheet
application = Application("My Test Application")
for doc in application["documents"]:
application.delete_resource(doc["id"])
Gets all log events for this fact sheet.
Returns the ["data"]
part of the API response object.
Reloads this fact sheet from LeanIX. Reloading is not done automatically due to performance reasons, so it can be done explicitly if required.
Example:
app.reload()
Sets (or breaks) the quality seal.
Possible values for status
: "APPROVED" (default), "DRAFT", "REJECTED", "BROKEN_QUALITY_SEAL"
Returns the URL that points to this fact sheet, including FQDN. Used in auto-generated e-mails.
Returns language-specific translated help texts and label translations for a fact sheet field.
Updates a fact sheet field.
update
parameter is a dict with keys name
(field to update) and value
(new value of the field).
For convenience, name + value can also be provided via keyword arguments.
Examples:
application = Application("...")
application.update_field(name="New name")
application.update_field(description="New description")
application.update_field(lifecycle={"phaseIn": "2020-01-01", "active": "2022-03-03"})
application.update_field(functionalSuitability="insufficient")
application.update_field(technicalSuitability="adequate")
Alternative, using old syntax:
application.update_field({"name": "/name", "value": "New name"})
application.update_field({"name": "/description", "value": "New description"})
Clones a fact sheet field and returns the new fact sheet's id.
use_as
can be either None, "Predecessor" or "Successor".
Examples:
app = Application("My application")
new_fs_id = app.clone(release=release, use_as="Successor", external_id="NewExtId")
new_app = Application(new_fs_id)
Creates a To-Do item for this fact sheet.
user_ids is a list of user ids.
category is either "ACTION_ITEM" for ToDos, or "ANSWER" for questions.
due_date is a string in format YYYY-mm-dd.
Alternatively, due_days is a number of days, so that due_date is calculated automatically.
Example:
app = Application("MyTest")
title = "My To-Do Item"
description = "My Description"
category = "ACTION_ITEM"
user_ids = [LeanIXUser.find_by_email("john.doe@example.com")["id"]]
due_date = "2029-12-31"
app.create_todo(title=title, description=description, category=category, user_ids=user_ids, due_date=due_date)
See create_todo, but checks if a to-do in status OPEN or IN_PROGRESS with the same title and description already exists.
See create_todo, but checks if a to-do in status OPEN or IN_PROGRESS with the same unique fields already exists, and updates the variable fields accordingly.
Loads all ToDos for this fact sheet. Currently only supports the "states" parameter. If you also need the other parameters, let me know.
Full parameter list that would be theoretically possible:
states: ["OPEN", "IN_PROGRESS", "CLOSED"]
categories: ["ACTION_ITEM", "ANSWER", "IMPORT", "LINK"]
claimedBy: List of user ids
assignees: List of user ids
creatorIds: List of user ids
dueDate: {"type": "RANGE", "value": {"from": "2023-10-29", "to": "2023-11-12"}}
creationDate: {"type": "RANGE", "value": {"from": "2023-11-12", "to": "2023-11-13"}}
resolutions: ["ACCEPTED", "REJECTED", "REVERTED", "NONE"]
Gets the SaaS catalog linking status of this fact sheet. In the resulting structure, "source" is the catalog item, "target" is the fact sheet.
Gets the lifecycle catalog linking status of this fact sheet. In the resulting structure, "source" is the catalog item, "target" is the fact sheet.
Gets the catalog linking status of this fact sheet in the catalog catalog
(saas or ltls). In the resulting structure, "source" is the
catalog item, "target" is the fact sheet.
Links the fact sheet to the SaaS catalog item item_id
. Set to None to delete a link and set it to "ignore".
Links the fact sheet to the lifecycle catalog item item_id
. Set to None to delete a link and set it to "ignore".
Links the fact sheet to the catalog item item_id
in the catalog named catalog
(saas or ltls). Set to None to delete a link and set it to "ignore".
Sets the given relation of this fact sheet to "leave empty" by adding the relation to the naFields
list
("Not Applicable Fields").
Example:
app = Application("My Application")
app.leave_empty("relApplicationToITComponent")
If a relation has been set to "leave empty", this method unsets this by removing the relation from the
naFields
list ("Not Applicable Fields"), so that relations can be added again.
Example:
app = Application("My Application")
app.should_not_be_empty("relApplicationToITComponent")
Returns suggestions from the LeanIX suggestions API based on the given query. See also quick_search
.
Returns results from the LeanIX quickSearch GraphQL function.
Compared to the suggestions
method, quickSearch also returns matches within a word. The query Test
will
match the fact sheet AppTest
, which is not the case for suggestions
.