Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/conda_env/environment_linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ dependencies:
- pytest-timeout
- psutil
- mpi4py
- dask=2022.01.0
- dask=2022.04.0
- dakota
- coverage<=6.2
2 changes: 1 addition & 1 deletion .github/workflows/conda_env/environment_macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ dependencies:
- pytest-cov
- pytest-timeout
- psutil
- dask=2022.01.0
- dask=2022.04.0
- coverage<=6.2
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ dependencies:
- pylint=2.11.1
- bandit=1.7.2
- codespell=2.1.0
- dask=2021.01.0
- dask=2022.04.0
- pytest
11 changes: 11 additions & 0 deletions doc/user_guides/advanced_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,17 @@ This section contains some useful tips on testing, debugging and documenting you
* Document the component code such that another person can understand how it works. It helps if the structure remains the same as the example component.
* Write a description of what the component does, the inputs it uses, outputs it produces, and what scenarios and modes it can be used in in the component documentation section.

* Protected attributes:

* The following Component attributes are used internally within IPS and are protected so you can not assigned to them:

* ``component_id``
* ``services``
* ``config``
* ``start_time``
* ``method_name``
* ``args``


-----------------
Writing Drivers
Expand Down
62 changes: 43 additions & 19 deletions ipsframework/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@ def __init__(self, services, config):
"""
Set up config values and reference to services.
"""
self.component_id = None
self.invocation_q = None
self.services = weakref.proxy(services)
self.config = config
self.start_time = 0.0
self.sys_exit = None
self.method_name = None
self.args = None
self.__component_id = None
self.__invocation_q = None
self.__services = weakref.proxy(services)
self.__config = config
self.__start_time = 0.0
self.__sys_exit = None
self.__method_name = None
self.__args = None
for i in config.keys():
try:
setattr(self, i, config[i])
Expand All @@ -44,7 +44,7 @@ def __copy__(self):
cls = self.__class__
result = cls.__new__(cls)
for k, v in self.__dict__.items():
if k in ["invocation_q", "sys_exit", "services"]:
if k in ["_Component__invocation_q", "_Component__sys_exit", "_Component__services"]:
setattr(result, k, None)
else:
setattr(result, k, copy(v))
Expand All @@ -54,9 +54,9 @@ def __initialize__(self, component_id, invocation_q, start_time=0.0):
"""
Establish connection to *invocation_q*.
"""
self.component_id = component_id
self.invocation_q = invocation_q
self.start_time = start_time
self.__component_id = component_id
self.__invocation_q = invocation_q
self.__start_time = start_time
# setattr(sys, 'exit', sys.exit)

def __my_exit__(self, arg=0):
Expand All @@ -77,7 +77,7 @@ def __run__(self):

tmp = sys.exit
sys.exit = self.__my_exit__
self.sys_exit = tmp
self.__sys_exit = tmp
try:
redirect = self.services.sim_conf['OUT_REDIRECT']
except KeyError:
Expand Down Expand Up @@ -119,15 +119,15 @@ def __run__(self):
self.services._init_event_service()

while True:
msg = self.invocation_q.get()
msg = self.__invocation_q.get()
self.services.log('Received Message ')
sender_id = msg.sender_id
call_id = msg.call_id
self.method_name = msg.target_method
self.args = msg.args
self.__method_name = msg.target_method
self.__args = msg.args
keywords = msg.keywords
formatted_args = ['%.3f' % (x) if isinstance(x, float)
else str(x) for x in self.args]
else str(x) for x in self.__args]
if keywords:
formatted_args += [" %s=" % k + str(v) for (k, v) in keywords.items()]

Expand All @@ -149,6 +149,30 @@ def __run__(self):
Message.SUCCESS, retval)
self.services.fwk_in_q.put(response_msg)

@property
def component_id(self):
return self.__component_id

@property
def services(self):
return self.__services

@property
def config(self):
return self.__config

@property
def start_time(self):
return self.__start_time

@property
def method_name(self):
return self.__method_name

@property
def args(self):
return self.__args

def init(self, timestamp=0.0, **keywords):
"""
Produce some default debugging information before the rest of the code
Expand Down Expand Up @@ -191,7 +215,7 @@ def terminate(self, status):
self.services.cleanup()
if status == Message.SUCCESS:
self.services.debug('Calling self.sys_exit(0)')
self.sys_exit(0)
self.__sys_exit(0)
else:
self.services.debug('Calling self.sys_exit(1)')
self.sys_exit(1)
self.__sys_exit(1)
1 change: 0 additions & 1 deletion ipsframework/portalBridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ def __init__(self, services, config):
self.host = ''
self.curTime = time.localtime()
self.startTime = self.curTime
self.services = services
self.sim_map = {}
self.portal_url = None
self.done = False
Expand Down
5 changes: 5 additions & 0 deletions tests/components/workers/bad_workers.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,8 @@ def step(self, timestamp=0.0, **keywords):
class exception_worker(Component):
def step(self, timestamp=0.0, **keywords):
raise RuntimeError('Runtime error')


class assign_protected_attribute(Component):
def step(self, timestamp=0.0, **keywords):
self.args = 0
28 changes: 28 additions & 0 deletions tests/new/test_bad_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,3 +164,31 @@ def test_bad_task_pool2(tmpdir):

assert "WORKER__bad_task_pool_worker2_2 ERROR Uncaught Exception in component method.\n" in lines
assert "DRIVER__driver_1 ERROR Uncaught Exception in component method.\n" in lines


def test_assign_protected_attribute(tmpdir):
platform_file, config_file = write_basic_config_and_platform_files(tmpdir, worker='assign_protected_attribute')

framework = Framework(config_file_list=[str(config_file)],
log_file_name=str(tmpdir.join('ips.log')),
platform_file_name=str(platform_file),
debug=None,
verbose_debug=None,
cmd_nodes=0,
cmd_ppn=0)

framework.run()

# check output log file
with open(str(tmpdir.join('sim.log')), 'r') as f:
lines = f.readlines()

# python 3.10 includes the attribute name in the error message
assert "AttributeError: can't set attribute\n" in lines or "AttributeError: can't set attribute 'args'\n" in lines
assert "Exception: can't set attribute\n" in lines or "Exception: can't set attribute 'args'\n" in lines

# remove timestamp
lines = [line[24:] for line in lines]

assert "WORKER__assign_protected_attribute_2 ERROR Uncaught Exception in component method.\n" in lines
assert "DRIVER__driver_1 ERROR Uncaught Exception in component method.\n" in lines