Skip to content
This repository has been archived by the owner on Nov 3, 2021. It is now read-only.

Udef checks dependencies #1615

Merged
merged 30 commits into from
Jul 22, 2021
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f2c6dd0
add method get_listeners
catunlock Jun 1, 2021
0848e13
add check for dependent elements before delete a element,
catunlock Jun 1, 2021
d498b1f
fix remove pydevd debugger
catunlock Jun 3, 2021
3e9fce8
improve dependent elements error message
catunlock Jun 3, 2021
510f4a3
improve get_dependent_elements
catunlock Jun 3, 2021
b28a6fd
clarifies message of dependent elements
catunlock Jun 3, 2021
35cb86a
remove pydevd
catunlock Jun 3, 2021
bdf0b53
add weakref to element in add_pseudo_elements
catunlock Jun 15, 2021
2b9359d
set to None all the posible referrers
catunlock Jun 15, 2021
644f9e2
Merge remote-tracking branch 'upstream/develop' into dependent_elements
reszelaz Jun 17, 2021
9929c10
style: fix PEP8 errors
reszelaz Jun 17, 2021
011e1a4
refactor: rename internal variable in get_dependent_elements()
reszelaz Jun 17, 2021
4569517
fix: pseudo elements weakref usage
reszelaz Jun 17, 2021
f22a614
refactor: do not delete references to element and ctrl in PseudoCounter
reszelaz Jun 17, 2021
7701e4c
fix: delete reference to core object in MotorGroup
reszelaz Jun 17, 2021
0ba422c
refactor: give better example in exception message
reszelaz Jun 17, 2021
08cfe48
Merge remote-tracking branch 'origin/develop' into dependent_elements
catunlock Jun 17, 2021
8efa6ac
refactor: remove __del__ introduced for debugging purposes
reszelaz Jun 17, 2021
45f38e3
fix: remove weakref from the list in remove_psuedo_element()
reszelaz Jun 17, 2021
c9599df
fix: do not pas meas grp as "head" kwarg to acquisition.prepare()
reszelaz Jun 29, 2021
e9a8900
fix: set PoolController.operator as weakref
reszelaz Jun 29, 2021
ff95a1e
test: fix order of deleting elements in tearDown()
reszelaz Jun 29, 2021
cf2851d
test: delete motor groups created in some tests
reszelaz Jun 29, 2021
97a96ee
fix: gc.collect() pseudo counters with cycle references
reszelaz Jun 29, 2021
146edfa
refactor: change return type of get_dependent_elements()
reszelaz Jul 20, 2021
b055e77
call gc.collect() only in case of PseudoCounters
reszelaz Jul 20, 2021
04f0ecf
Merge remote-tracking branch 'upstream/develop' into dependent_elements
reszelaz Jul 20, 2021
6ac7aa6
fix: meas group with undefined disabled channel
reszelaz Jul 21, 2021
7f84584
add has_dependent_elements() to PoolBaseElement
reszelaz Jul 22, 2021
563e299
fix: gc.collect() of dependent elements
reszelaz Jul 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/sardana/macroserver/macros/test/test_scanct.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
##############################################################################

"""Tests for continuous scans (ct-like)"""
import json
import time
import PyTango
import unittest
Expand Down Expand Up @@ -333,6 +334,8 @@ def macro_stops(self, meas_config, macro_params, wait_timeout=None,
ScanctTest.check_stopped(self)

def tearDown(self):
for mg in self.pool.MotorGroupList:
self.pool.DeleteElement(json.loads(mg)['name'])
ScanctTest.tearDown(self)
unittest.TestCase.tearDown(self)

Expand Down Expand Up @@ -388,5 +391,7 @@ def macro_stops(self, meas_config, macro_params, wait_timeout=None,
ScanctTest.check_stopped(self)

def tearDown(self):
for mg in self.pool.MotorGroupList:
self.pool.DeleteElement(json.loads(mg)['name'])
ScanctTest.tearDown(self)
unittest.TestCase.tearDown(self)
14 changes: 14 additions & 0 deletions src/sardana/pool/pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@

__docformat__ = 'restructuredtext'

import gc
import os.path
import logging.handlers

Expand Down Expand Up @@ -557,6 +558,19 @@ def delete_element(self, name):
raise Exception("There is no element with name '%s'" % name)

elem_type = elem.get_type()
dependent_elements = elem.get_dependent_elements()
if len(dependent_elements) > 0:
gc.collect()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

perhaps a comment regarding why this is required here in the PR description?

dependent_elements = elem.get_dependent_elements()
if len(dependent_elements) > 0:
raise Exception(
"The element {} can't be deleted because {} depend on it."
"\n\nIf the name of the dependent element starts with "
"'_mg_ms_*' it means that are motor groups, execute "
"DeleteElement(<motor_group_name>) command on the Pool e.g. "
"Pool_demo1_1.DeleteElement('_mg_ms_20671_1') in Spock."
.format(name, ", ".join(dependent_elements)))

if elem_type == ElementType.Controller:
if len(elem.get_elements()) > 0:
raise Exception("Cannot delete controller with elements. "
Expand Down
2 changes: 1 addition & 1 deletion src/sardana/pool/poolacquisition.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ def run(self, *args, **kwargs):
# clean also the pseudo counters, even the ones that do not
# participate directly in the acquisition
for pseudo_elem in elem.get_pseudo_elements():
pseudo_elem.clear_value_buffer()
pseudo_elem().clear_value_buffer()

if self._hw_acq_args is not None:
self._hw_acq._wait()
Expand Down
26 changes: 18 additions & 8 deletions src/sardana/pool/poolbasechannel.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@

__docformat__ = 'restructuredtext'

import weakref

from sardana.sardanadefs import AttrQuality, ElementType
from sardana.sardanaattribute import SardanaAttribute
from sardana.sardanabuffer import SardanaBuffer
Expand All @@ -41,6 +43,7 @@
from sardana.sardanaevent import EventType
from sardana.pool import AcqSynch, AcqMode


class ValueBuffer(SardanaBuffer):

def is_value_required(self, idx):
Expand All @@ -53,7 +56,7 @@ def is_value_required(self, idx):
:rtype: bool
"""
for element in self.obj.get_pseudo_elements():
if element.get_value_buffer().next_idx <= idx:
if element().get_value_buffer().next_idx <= idx:
return True
return False

Expand Down Expand Up @@ -135,8 +138,8 @@ def get_pseudo_elements(self):
"""Returns list of pseudo elements e.g. pseudo counters that this
channel belongs to.
:return: pseudo elements
:rtype: seq<:class:`~sardana.pool.poolpseudocounter.PoolPseudoCounter`>
:return: weak references to pseudo elements
:rtype: seq<:class:`weakref.ref`>
"""
return self._pseudo_elements

Expand All @@ -150,7 +153,7 @@ def add_pseudo_element(self, element):
"""
if not self.has_pseudo_elements():
self.get_value_buffer().persistent = True
self._pseudo_elements.append(element)
self._pseudo_elements.append(weakref.ref(element))

def remove_pseudo_element(self, element):
"""Removes pseudo element e.g. pseudo counters that this channel
Expand All @@ -160,10 +163,17 @@ def remove_pseudo_element(self, element):
:type element:
:class:`~sardana.pool.poolpseudocounter.PoolPseudoCounter`
"""

self._pseudo_elements.remove(element)
if not self.has_pseudo_elements():
self.get_value_buffer().persistent = False
for pseudo_element in self._pseudo_elements:
if pseudo_element() == element:
self._pseudo_elements.remove(pseudo_element)
if not self.has_pseudo_elements():
self.get_value_buffer().persistent = False
break
else:
raise ValueError(
"{} is not a pseudo element of {}".format(
element.name, self.name)
)

def get_value_attribute(self):
"""Returns the value attribute object for this experiment channel
Expand Down
3 changes: 3 additions & 0 deletions src/sardana/pool/poolbaseelement.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ def serialize(self, *args, **kwargs):
ret = PoolObject.serialize(self, *args, **kwargs)
return ret

def get_dependent_elements(self):
return []

# --------------------------------------------------------------------------
# simulation mode
# --------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions src/sardana/pool/poolcontroller.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,10 @@ def set_operator(self, operator):
:param operator: the new operator object
:type operator: object"""
self._operator = operator
self._operator = weakref.ref(operator)

def get_operator(self):
return self._operator
return self._operator()

operator = property(fget=get_operator, fset=set_operator,
doc="current controller operator")
Expand Down
15 changes: 15 additions & 0 deletions src/sardana/pool/poolelement.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,21 @@ def set_action_cache(self, action_cache):
def get_source(self):
return "{0}/{1}".format(self.full_name, self.get_default_acquisition_channel())

def get_dependent_elements(self):
dependent_elements = []
for listener in self.get_listeners():
try:
elem = listener().__self__
except AttributeError:
continue
if isinstance(elem, PoolBaseElement):
dependent_elements.append(elem.name)

return dependent_elements

def has_dependent_elements(self):
return len(self.get_dependent_elements()) > 0

# --------------------------------------------------------------------------
# instrument
# --------------------------------------------------------------------------
Expand Down
5 changes: 1 addition & 4 deletions src/sardana/pool/poolmeasurementgroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -1345,16 +1345,13 @@ def prepare(self):
value = self._get_value()
self._pending_starts = self.nb_starts

kwargs = {'head': self}

self.acquisition.prepare(self.configuration,
self.acquisition_mode,
value,
self._synch_description,
self._moveable_obj,
self.sw_synch_initial_domain,
self.nb_starts,
**kwargs)
self.nb_starts)

def start_acquisition(self, value=None):
"""Start measurement.
Expand Down
3 changes: 3 additions & 0 deletions src/sardana/sardanaevent.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ def has_listeners(self):
return False
return len(self._listeners) > 0

def get_listeners(self):
return self._listeners

def fire_event(self, event_type, event_value, listeners=None):
self.flush_queue()
self._fire_event(event_type, event_value, listeners=listeners)
Expand Down
1 change: 1 addition & 0 deletions src/sardana/tango/pool/Controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ def set_ctrl(self, ctrl):
@DebugIt()
def delete_device(self):
PoolDevice.delete_device(self)
self.ctrl = None

@DebugIt()
def init_device(self):
Expand Down
1 change: 1 addition & 0 deletions src/sardana/tango/pool/MeasurementGroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def delete_device(self):
mg = self.measurement_group
if mg is not None:
mg.remove_listener(self.on_measurement_group_changed)
self.measurement_group = None

@DebugIt()
def init_device(self):
Expand Down
1 change: 1 addition & 0 deletions src/sardana/tango/pool/MotorGroup.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ def delete_device(self):
motor_group = self.motor_group
if motor_group is not None:
motor_group.remove_listener(self.on_motor_group_changed)
self.motor_group = None

@DebugIt()
def init_device(self):
Expand Down
1 change: 1 addition & 0 deletions src/sardana/tango/pool/PseudoCounter.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ def delete_device(self):
pseudo_counter = self.pseudo_counter
if pseudo_counter is not None:
pseudo_counter.remove_listener(self.on_pseudo_counter_changed)
self.pseudo_counter = None

@DebugIt()
def init_device(self):
Expand Down
1 change: 1 addition & 0 deletions src/sardana/tango/pool/PseudoMotor.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ def delete_device(self):
pseudo_motor = self.pseudo_motor
if pseudo_motor is not None:
pseudo_motor.remove_listener(self.on_pseudo_motor_changed)
self.pseudo_motor = None

@DebugIt()
def init_device(self):
Expand Down
80 changes: 46 additions & 34 deletions src/sardana/tango/pool/test/base_sartest.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ def setUp(self, pool_properties=None):

self.ctrl_list = []
self.elem_list = []
self.pseudo_ctrl_list = []
self.pseudo_elem_list = []
try:
# physical controllers and elements
for sar_type, lib, cls, prefix, postfix, nelem in self.cls_list:
Expand Down Expand Up @@ -145,58 +147,68 @@ def setUp(self, pool_properties=None):
print(e)
msg = 'Impossible to create ctrl: "%s"' % (ctrl_name)
raise Exception('Aborting SartestTestCase: %s' % (msg))
self.ctrl_list.append(ctrl_name)
self.pseudo_ctrl_list.append(ctrl_name)
for role in roles:
elem = role.split("=")[1]
if elem not in self.elem_list:
self.elem_list.append(elem)
self.pseudo_elem_list.append(elem)
except Exception as e:
# force tearDown in order to eliminate the Pool
BasePoolTestCase.tearDown(self)
print(e)

def _delete_elem(self, elem_name):
# Cleanup eventual taurus devices. This is especially important
# if the sardana-taurus extensions are in use since this
# devices are created and destroyed within the testsuite.
# Persisting taurus device may react on API_EventTimeouts, enabled
# polling, etc.
if elem_name in self.f.tango_alias_devs:
_cleanup_device(elem_name)
try:
if os.name != "nt":
self.pool.DeleteElement(elem_name)
print(elem_name)
except Exception as e:
print(e)
self.dirty_elems.append(elem_name)

def _delete_ctrl(self, ctrl_name):
# Cleanup eventual taurus devices. This is especially important
# if the sardana-taurus extensions are in use since this
# devices are created and destroyed within the testsuite.
# Persisting taurus device may react on API_EventTimeouts, enabled
# polling, etc.
if ctrl_name in self.f.tango_alias_devs:
_cleanup_device(ctrl_name)
try:
if os.name != "nt":
self.pool.DeleteElement(ctrl_name)
print(ctrl_name)
except:
self.dirty_ctrls.append(ctrl_name)

def tearDown(self):
"""Remove the elements and the controllers
"""
dirty_elems = []
dirty_ctrls = []
f = taurus.Factory()
self.dirty_elems = []
self.dirty_ctrls = []
self.f = taurus.Factory()
for elem_name in self.pseudo_elem_list:
self._delete_elem(elem_name)
for ctrl_name in self.pseudo_ctrl_list:
self._delete_ctrl(ctrl_name)
for elem_name in self.elem_list:
# Cleanup eventual taurus devices. This is especially important
# if the sardana-taurus extensions are in use since this
# devices are created and destroyed within the testsuite.
# Persisting taurus device may react on API_EventTimeouts, enabled
# polling, etc.
if elem_name in f.tango_alias_devs:
_cleanup_device(elem_name)
try:
if os.name != "nt":
self.pool.DeleteElement(elem_name)
except Exception as e:
print(e)
dirty_elems.append(elem_name)

self._delete_elem(elem_name)
for ctrl_name in self.ctrl_list:
# Cleanup eventual taurus devices. This is especially important
# if the sardana-taurus extensions are in use since this
# devices are created and destroyed within the testsuite.
# Persisting taurus device may react on API_EventTimeouts, enabled
# polling, etc.
if ctrl_name in f.tango_alias_devs:
_cleanup_device(ctrl_name)
try:
if os.name != "nt":
self.pool.DeleteElement(ctrl_name)
except:
dirty_ctrls.append(ctrl_name)

self._delete_ctrl(ctrl_name)
_cleanup_device(self.pool_name)

BasePoolTestCase.tearDown(self)

if dirty_elems or dirty_ctrls:
if self.dirty_elems or self.dirty_ctrls:
msg = "Cleanup failed. Database may be left dirty." + \
"\n\tCtrls : %s\n\tElems : %s" % (dirty_ctrls, dirty_elems)
"\n\tCtrls : %s\n\tElems : %s" % (self.dirty_ctrls, self.dirty_elems)
raise Exception(msg)


Expand Down