Passed
Push — master ( a7d9df...9e2c55 )
by Jordi
05:41
created

bika.lims.api.analysisservice   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 142
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 17
eloc 62
dl 0
loc 142
rs 10
c 0
b 0
f 0

3 Functions

Rating   Name   Duplication   Size   Complexity  
B get_calculation_dependants_for() 0 60 8
B get_calculation_dependencies_for() 0 56 8
A get_service_dependencies_for() 0 10 1
1
# -*- coding: utf-8 -*-
2
#
3
# This file is part of SENAITE.CORE
4
#
5
# Copyright 2018 by it's authors.
6
# Some rights reserved. See LICENSE.rst, CONTRIBUTORS.rst.
7
8
from bika.lims import api
9
from bika.lims.browser.fields.uidreferencefield import get_backreferences
10
11
12
def get_calculation_dependants_for(service):
13
    """Collect all services which depend on this service
14
15
    :param service: Analysis Service Object/ZCatalog Brain
16
    :returns: List of services that depend on this service
17
    """
18
19
    def calc_dependants_gen(service, collector=None):
20
        """Generator for recursive resolution of dependant sevices.
21
        """
22
23
        # The UID of the service
24
        service_uid = api.get_uid(service)
25
26
        # maintain an internal dependency mapping
27
        if collector is None:
28
            collector = {}
29
30
        # Stop iteration if we processed this service already
31
        if service_uid in collector:
32
            raise StopIteration
33
34
        # Get the dependant calculations of the service
35
        # (calculations that use the service in their formula).
36
        calc_uids = get_backreferences(
37
            service, relationship="CalculationDependentServices")
38
39
        for calc_uid in calc_uids:
40
            # Get the calculation object
41
            calc = api.get_object_by_uid(calc_uid)
42
43
            # Get the Analysis Services which have this calculation assigned
44
            dep_service_uids = get_backreferences(
45
                calc, relationship='AnalysisServiceCalculation')
46
47
            for dep_service_uid in dep_service_uids:
48
                dep_service = api.get_object_by_uid(dep_service_uid)
49
50
                # remember the dependent service
51
                collector[dep_service_uid] = dep_service
52
53
                # yield the dependent service
54
                yield dep_service
55
56
                # check the dependants of the dependant services
57
                for ddep_service in calc_dependants_gen(
58
                        dep_service, collector=collector):
59
                    yield ddep_service
60
61
    dependants = {}
62
    service = api.get_object(service)
63
64
    for dep_service in calc_dependants_gen(service):
65
        # Skip the initial (requested) service
66
        if dep_service == service:
67
            continue
68
        uid = api.get_uid(dep_service)
69
        dependants[uid] = dep_service
70
71
    return dependants
72
73
74
def get_calculation_dependencies_for(service):
75
    """Calculation dependencies of this service and the calculation of each
76
    dependent service (recursively).
77
    """
78
79
    def calc_dependencies_gen(service, collector=None):
80
        """Generator for recursive dependency resolution.
81
        """
82
83
        # The UID of the service
84
        service_uid = api.get_uid(service)
85
86
        # maintain an internal dependency mapping
87
        if collector is None:
88
            collector = {}
89
90
        # Stop iteration if we processed this service already
91
        if service_uid in collector:
92
            raise StopIteration
93
94
        # Get the calculation of the service.
95
        # The calculation comes either from an assigned method or the user
96
        # has set a calculation manually (see content/analysisservice.py).
97
        calculation = service.getCalculation()
98
99
        # Stop iteration if there is no calculation
100
        if not calculation:
101
            raise StopIteration
102
103
        # The services used in this calculation.
104
        # These are the actual dependencies of the used formula.
105
        dep_services = calculation.getDependentServices()
106
        for dep_service in dep_services:
107
            # get the UID of the dependent service
108
            dep_service_uid = api.get_uid(dep_service)
109
110
            # remember the dependent service
111
            collector[dep_service_uid] = dep_service
112
113
            # yield the dependent service
114
            yield dep_service
115
116
            # check the dependencies of the dependent services
117
            for ddep_service in calc_dependencies_gen(dep_service,
118
                                                      collector=collector):
119
                yield ddep_service
120
121
    dependencies = {}
122
    for dep_service in calc_dependencies_gen(service):
123
        # Skip the initial (requested) service
124
        if dep_service == service:
125
            continue
126
        uid = api.get_uid(dep_service)
127
        dependencies[uid] = dep_service
128
129
    return dependencies
130
131
132
def get_service_dependencies_for(service):
133
    """Calculate the dependencies for the given service.
134
    """
135
136
    dependants = get_calculation_dependants_for(service)
137
    dependencies = get_calculation_dependencies_for(service)
138
139
    return {
140
        "dependencies": dependencies.values(),
141
        "dependants": dependants.values(),
142
    }
143