Conditions | 19 |
Total Lines | 139 |
Code Lines | 62 |
Lines | 0 |
Ratio | 0 % |
Changes | 0 |
Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.
For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.
Commonly applied refactorings include:
If many parameters/temporary variables are present:
Complex classes like bika.lims.browser.fields.aranalysesfield.ARAnalysesField.set() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
1 | # -*- coding: utf-8 -*- |
||
75 | def set(self, instance, items, prices=None, specs=None, **kwargs): |
||
76 | """Set/Assign Analyses to this AR |
||
77 | |||
78 | :param items: List of Analysis objects/brains, AnalysisService |
||
79 | objects/brains and/or Analysis Service uids |
||
80 | :type items: list |
||
81 | :param prices: Mapping of AnalysisService UID -> price |
||
82 | :type prices: dict |
||
83 | :param specs: List of AnalysisService UID -> Result Range mappings |
||
84 | :type specs: list |
||
85 | :returns: list of new assigned Analyses |
||
86 | """ |
||
87 | |||
88 | # This setter returns a list of new set Analyses |
||
89 | new_analyses = [] |
||
90 | |||
91 | # Current assigned analyses |
||
92 | analyses = instance.objectValues("Analysis") |
||
93 | |||
94 | # Analyses which are in a non-open state must be retained |
||
95 | non_open_analyses = filter(lambda an: not an.isOpen(), analyses) |
||
96 | |||
97 | # Prevent removing all analyses |
||
98 | # |
||
99 | # N.B.: Non-open analyses are rendered disabled in the HTML form. |
||
100 | # Therefore, their UIDs are not included in the submitted UIDs. |
||
101 | if not items and not non_open_analyses: |
||
102 | logger.warn("Not allowed to remove all Analyses from AR.") |
||
103 | return new_analyses |
||
104 | |||
105 | # Bail out if the items is not a list type |
||
106 | if not isinstance(items, (list, tuple)): |
||
107 | raise TypeError( |
||
108 | "Items parameter must be a tuple or list, got '{}'".format( |
||
109 | type(items))) |
||
110 | |||
111 | # Bail out if the AR is inactive |
||
112 | if not api.is_active(instance): |
||
113 | raise Unauthorized("Inactive ARs can not be modified" |
||
114 | .format(AddAnalysis)) |
||
115 | |||
116 | # Bail out if the user has not the right permission |
||
117 | sm = getSecurityManager() |
||
118 | if not sm.checkPermission(AddAnalysis, instance): |
||
119 | raise Unauthorized("You do not have the '{}' permission" |
||
120 | .format(AddAnalysis)) |
||
121 | |||
122 | # Convert the items to a valid list of AnalysisServices |
||
123 | services = filter(None, map(self._to_service, items)) |
||
124 | |||
125 | # Calculate dependencies |
||
126 | # FIXME Infinite recursion error possible here, if the formula includes |
||
127 | # the Keyword of the Service that includes the Calculation |
||
128 | dependencies = map(lambda s: s.getServiceDependencies(), services) |
||
129 | dependencies = list(itertools.chain.from_iterable(dependencies)) |
||
130 | |||
131 | # Merge dependencies and services |
||
132 | services = set(services + dependencies) |
||
133 | |||
134 | # Modify existing AR specs with new form values of selected analyses. |
||
135 | self._update_specs(instance, specs) |
||
136 | |||
137 | # CREATE/MODIFY ANALYSES |
||
138 | |||
139 | for service in services: |
||
140 | keyword = service.getKeyword() |
||
141 | |||
142 | # Create the Analysis if it doesn't exist |
||
143 | if shasattr(instance, keyword): |
||
144 | analysis = instance._getOb(keyword) |
||
145 | else: |
||
146 | analysis = create_analysis(instance, service) |
||
147 | new_analyses.append(analysis) |
||
148 | |||
149 | # Set the price of the Analysis |
||
150 | self._update_price(analysis, service, prices) |
||
151 | |||
152 | # DELETE ANALYSES |
||
153 | |||
154 | # Service UIDs |
||
155 | service_uids = map(api.get_uid, services) |
||
156 | |||
157 | # Analyses IDs to delete |
||
158 | delete_ids = [] |
||
159 | |||
160 | # Assigned Attachments |
||
161 | assigned_attachments = [] |
||
162 | |||
163 | for analysis in analyses: |
||
164 | service_uid = analysis.getServiceUID() |
||
165 | |||
166 | # Skip if the Service is selected |
||
167 | if service_uid in service_uids: |
||
168 | continue |
||
169 | |||
170 | # Skip non-open Analyses |
||
171 | if analysis in non_open_analyses: |
||
172 | continue |
||
173 | |||
174 | # Remember assigned attachments |
||
175 | # https://github.com/senaite/senaite.core/issues/1025 |
||
176 | assigned_attachments.extend(analysis.getAttachment()) |
||
177 | analysis.setAttachment([]) |
||
178 | |||
179 | # If it is assigned to a worksheet, unassign it before deletion. |
||
180 | worksheet = analysis.getWorksheet() |
||
181 | if worksheet: |
||
182 | worksheet.removeAnalysis(analysis) |
||
183 | |||
184 | # Unset the partition reference |
||
185 | part = analysis.getSamplePartition() |
||
186 | if part: |
||
187 | # From this partition, remove the reference to the current |
||
188 | # analysis that is going to be removed to prevent inconsistent |
||
189 | # states (Sample Partitions referencing to Analyses that do not |
||
190 | # exist anymore |
||
191 | an_uid = api.get_uid(analysis) |
||
192 | part_ans = part.getAnalyses() or [] |
||
193 | part_ans = filter( |
||
194 | lambda an: api.get_uid(an) != an_uid, part_ans) |
||
|
|||
195 | part.setAnalyses(part_ans) |
||
196 | # Unset the Analysis-to-Partition reference |
||
197 | analysis.setSamplePartition(None) |
||
198 | delete_ids.append(analysis.getId()) |
||
199 | |||
200 | if delete_ids: |
||
201 | # Note: subscriber might promote the AR |
||
202 | instance.manage_delObjects(ids=delete_ids) |
||
203 | |||
204 | # Remove orphaned attachments |
||
205 | for attachment in assigned_attachments: |
||
206 | # only delete attachments which are no further linked |
||
207 | if not attachment.getLinkedAnalyses(): |
||
208 | logger.info( |
||
209 | "Deleting attachment: {}".format(attachment.getId())) |
||
210 | attachment_id = api.get_id(attachment) |
||
211 | api.get_parent(attachment).manage_delObjects(attachment_id) |
||
212 | |||
213 | return new_analyses |
||
214 | |||
298 |