From 8ce56ccfe63e56061e65b2f9a033e3eeaa6f921f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Tue, 5 Feb 2019 16:12:42 +0100 Subject: [PATCH 01/10] extend static_isinstance to support lists of job types --- pyiron/base/job/jobtype.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pyiron/base/job/jobtype.py b/pyiron/base/job/jobtype.py index 01c016e40..df7ce2eeb 100644 --- a/pyiron/base/job/jobtype.py +++ b/pyiron/base/job/jobtype.py @@ -150,4 +150,10 @@ def convert_str_to_class(job_class_dict, class_name): def static_isinstance(obj, obj_type): - return obj_type in ['.'.join([subcls.__module__, subcls.__name__]) for subcls in obj.__mro__] + obj_class_lst = ['.'.join([subcls.__module__, subcls.__name__]) for subcls in obj.__mro__] + if isinstance(obj_type, list): + return any([obj_type_element in obj_class_lst for obj_type_element in obj_type]) + elif isinstance(obj_type, str): + return obj_type in obj_class_lst + else: + raise TypeError() From 37ad9baf7f756b8de57a2295084e88a95f8144dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Tue, 5 Feb 2019 16:16:32 +0100 Subject: [PATCH 02/10] add docstrings --- pyiron/base/job/jobtype.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pyiron/base/job/jobtype.py b/pyiron/base/job/jobtype.py index df7ce2eeb..c38361547 100644 --- a/pyiron/base/job/jobtype.py +++ b/pyiron/base/job/jobtype.py @@ -135,6 +135,16 @@ def __new__(cls, class_name, project, job_name, job_class_dict): @staticmethod def convert_str_to_class(job_class_dict, class_name): + """ + convert the name of a class to the corresponding class object - only for pyiron internal classes. + + Args: + job_class_dict (dict): + class_name (str): + + Returns: + (class): + """ job_type_lst = class_name.split(".") if len(job_type_lst) > 1: class_name = class_name.split()[-1][1:-2] @@ -150,6 +160,17 @@ def convert_str_to_class(job_class_dict, class_name): def static_isinstance(obj, obj_type): + """ + A static implementation of isinstance() - instead of comparing an object and a class, the object is compared to a + string, like 'pyiron.base.job.generic.GenericJob' or a list of strings. + + Args: + obj: the object to check + obj_type (str/list): object type as string or a list of object types as string. + + Returns: + bool: [True/False] + """ obj_class_lst = ['.'.join([subcls.__module__, subcls.__name__]) for subcls in obj.__mro__] if isinstance(obj_type, list): return any([obj_type_element in obj_class_lst for obj_type_element in obj_type]) From 0779aefaf551be556f04089c7a6f6b00d60949b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Tue, 5 Feb 2019 16:17:28 +0100 Subject: [PATCH 03/10] Implement create_job on the GenericJob level - if a MasterJob is created the corresponding job (self) is set as reference job. --- pyiron/base/job/generic.py | 58 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/pyiron/base/job/generic.py b/pyiron/base/job/generic.py index b32d2c2a7..11051b461 100644 --- a/pyiron/base/job/generic.py +++ b/pyiron/base/job/generic.py @@ -16,6 +16,7 @@ from pyiron.base.job.executable import Executable from pyiron.base.job.jobstatus import JobStatus from pyiron.base.job.core import JobCore +from pyiron.base.job.jobtype import static_isinstance from pyiron.base.server.generic import Server import subprocess import shutil @@ -739,6 +740,63 @@ def send_to_database(self): if self.server.send_to_db: pass + def create_job(self, job_type, job_name): + """ + Create one of the following jobs: + - 'StructureContainer’: + - ‘StructurePipeline’: + - ‘AtomisticExampleJob’: example job just generating random number + - ‘ExampleJob’: example job just generating random number + - ‘Lammps’: + - ‘KMC’: + - ‘Sphinx’: + - ‘Vasp’: + - ‘GenericMaster’: + - ‘SerialMaster’: series of jobs run in serial + - ‘AtomisticSerialMaster’: + - ‘ParallelMaster’: series of jobs run in parallel + - ‘KmcMaster’: + - ‘ThermoLambdaMaster’: + - ‘RandomSeedMaster’: + - ‘MeamFit’: + - ‘Murnaghan’: + - ‘MinimizeMurnaghan’: + - ‘ElasticMatrix’: + - ‘ConvergenceVolume’: + - ‘ConvergenceEncutParallel’: + - ‘ConvergenceKpointParallel’: + - ’PhonopyMaster’: + - ‘DefectFormationEnergy’: + - ‘LammpsASE’: + - ‘PipelineMaster’: + - ’TransformationPath’: + - ‘ThermoIntEamQh’: + - ‘ThermoIntDftEam’: + - ‘ScriptJob’: Python script or jupyter notebook job container + - ‘ListMaster': list of jobs + + Args: + job_type (str): job type can be ['StructureContainer’, ‘StructurePipeline’, ‘AtomisticExampleJob’, + ‘ExampleJob’, ‘Lammps’, ‘KMC’, ‘Sphinx’, ‘Vasp’, ‘GenericMaster’, + ‘SerialMaster’, ‘AtomisticSerialMaster’, ‘ParallelMaster’, ‘KmcMaster’, + ‘ThermoLambdaMaster’, ‘RandomSeedMaster’, ‘MeamFit’, ‘Murnaghan’, + ‘MinimizeMurnaghan’, ‘ElasticMatrix’, ‘ConvergenceVolume’, + ‘ConvergenceEncutParallel’, ‘ConvergenceKpointParallel’, ’PhonopyMaster’, + ‘DefectFormationEnergy’, ‘LammpsASE’, ‘PipelineMaster’, + ’TransformationPath’, ‘ThermoIntEamQh’, ‘ThermoIntDftEam’, ‘ScriptJob’, + ‘ListMaster'] + job_name (str): name of the job + + Returns: + GenericJob: job object depending on the job_type selected + """ + job = self.project.create_job(job_type=job_type, job_name=job_name) + if static_isinstance(obj=job, obj_type=['pyiron.base.master.parallel.ParallelMaster', + 'pyiron.base.master.serial.SerialMasterBase', + 'pyiron.atomistic.job.interactivewrapper.InteractiveWrapper']): + job.ref_job = self + return job + def update_master(self): """ After a job is finished it checks whether it is linked to any metajob - meaning the master ID is pointing to From 3ed3ad8813777cd7c632be73e21b961a471d42f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Wed, 6 Feb 2019 08:14:53 +0100 Subject: [PATCH 04/10] static_isinstance - now works with classes as well as objects --- pyiron/base/job/jobtype.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyiron/base/job/jobtype.py b/pyiron/base/job/jobtype.py index c38361547..462154a88 100644 --- a/pyiron/base/job/jobtype.py +++ b/pyiron/base/job/jobtype.py @@ -171,6 +171,8 @@ def static_isinstance(obj, obj_type): Returns: bool: [True/False] """ + if not hasattr(obj, '__mro__'): + obj = obj.__class__ obj_class_lst = ['.'.join([subcls.__module__, subcls.__name__]) for subcls in obj.__mro__] if isinstance(obj_type, list): return any([obj_type_element in obj_class_lst for obj_type_element in obj_type]) From 43f93b0124a6a83fcc5a56f16820db08bc4f9f34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Wed, 6 Feb 2019 08:15:55 +0100 Subject: [PATCH 05/10] create_job(): if job is run_mode non_modal set master to be run_mode non_modal. --- pyiron/base/job/generic.py | 27 ++++++--------------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/pyiron/base/job/generic.py b/pyiron/base/job/generic.py index 11051b461..bb65b066d 100644 --- a/pyiron/base/job/generic.py +++ b/pyiron/base/job/generic.py @@ -791,10 +791,13 @@ def create_job(self, job_type, job_name): GenericJob: job object depending on the job_type selected """ job = self.project.create_job(job_type=job_type, job_name=job_name) - if static_isinstance(obj=job, obj_type=['pyiron.base.master.parallel.ParallelMaster', - 'pyiron.base.master.serial.SerialMasterBase', - 'pyiron.atomistic.job.interactivewrapper.InteractiveWrapper']): + if static_isinstance(obj=job.__class__, + obj_type=['pyiron.base.master.parallel.ParallelMaster', + 'pyiron.base.master.serial.SerialMasterBase', + 'pyiron.atomistic.job.interactivewrapper.InteractiveWrapper']): job.ref_job = self + if self.server.run_mode.non_modal: + job.server.run_mode.non_modal = True return job def update_master(self): @@ -959,24 +962,6 @@ def restart(self, snapshot=-1, job_name=None, job_type=None): new_ham._restart_file_dict = dict() return new_ham - def create_job(self, job_type, job_name): - """ - Create one of the following jobs: - - 'ExampleJob': example job just generating random number - - 'SerialMaster': series of jobs run in serial - - 'ParallelMaster': series of jobs run in parallel - - 'ScriptJob': Python script or jupyter notebook job container - - 'ListMaster': list of jobs - - Args: - job_type (str): job type can be ['ExampleJob', 'SerialMaster', 'ParallelMaster', 'ScriptJob', 'ListMaster'] - job_name (str): name of the job - - Returns: - GenericJob: job object depending on the job_type selected - """ - return self.project.create_job(job_type=job_type, job_name=job_name) - def _copy_restart_files(self): """ Internal helper function to copy the files required for the restart job. From 07ae5af704c3797b4c96aeed87bea3bc47b6f700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Wed, 6 Feb 2019 08:30:01 +0100 Subject: [PATCH 06/10] create_job(): if job is run_mode interactive or interactive_non_modal set master to be run_mode interactive. --- pyiron/base/job/generic.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyiron/base/job/generic.py b/pyiron/base/job/generic.py index bb65b066d..4a08bc8d1 100644 --- a/pyiron/base/job/generic.py +++ b/pyiron/base/job/generic.py @@ -798,6 +798,8 @@ def create_job(self, job_type, job_name): job.ref_job = self if self.server.run_mode.non_modal: job.server.run_mode.non_modal = True + elif self.server.run_mode.interactive or self.server.run_mode.interactive_non_modal: + job.server.run_mode.interactive = True return job def update_master(self): From ed3af2835565b803e4e452abf17276e625d0d245 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Wed, 6 Feb 2019 08:43:33 +0100 Subject: [PATCH 07/10] Add unit tests --- __init__.py | 0 tests/base/job/test_jobtype.py | 15 +++++++++++++++ 2 files changed, 15 insertions(+) create mode 100644 __init__.py create mode 100644 tests/base/job/test_jobtype.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/base/job/test_jobtype.py b/tests/base/job/test_jobtype.py new file mode 100644 index 000000000..a32bb2ef0 --- /dev/null +++ b/tests/base/job/test_jobtype.py @@ -0,0 +1,15 @@ +import unittest +from pyiron.base.job.jobtype import static_isinstance + + +class TestJobType(unittest.TestCase): + def test_static_isinstance(self): + self.assertTrue(static_isinstance(obj=list(), obj_type=['builtins.list', 'builtins.object'])) + self.assertTrue(static_isinstance(obj=list(), obj_type='builtins.list')) + self.assertTrue(static_isinstance(obj=list().__class__, obj_type='builtins.list')) + with self.assertRaises(TypeError) as context: + self.assertTrue(static_isinstance(obj=list(), obj_type=1)) + + +if __name__ == '__main__': + unittest.main() From 20cb71e1ac7f0da8e66c98c46e02acd71a11328b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Wed, 6 Feb 2019 08:53:53 +0100 Subject: [PATCH 08/10] fix test --- tests/base/job/test_jobtype.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/base/job/test_jobtype.py b/tests/base/job/test_jobtype.py index a32bb2ef0..9c5697be1 100644 --- a/tests/base/job/test_jobtype.py +++ b/tests/base/job/test_jobtype.py @@ -7,8 +7,7 @@ def test_static_isinstance(self): self.assertTrue(static_isinstance(obj=list(), obj_type=['builtins.list', 'builtins.object'])) self.assertTrue(static_isinstance(obj=list(), obj_type='builtins.list')) self.assertTrue(static_isinstance(obj=list().__class__, obj_type='builtins.list')) - with self.assertRaises(TypeError) as context: - self.assertTrue(static_isinstance(obj=list(), obj_type=1)) + self.assertRaises(TypeError, static_isinstance, list(), 1) if __name__ == '__main__': From 5e5879c361b8f06c9917fff3caa62892b8788191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Wed, 6 Feb 2019 09:36:26 +0100 Subject: [PATCH 09/10] Python 2.7 compatibility --- tests/base/job/test_jobtype.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/base/job/test_jobtype.py b/tests/base/job/test_jobtype.py index 9c5697be1..5a67d21cc 100644 --- a/tests/base/job/test_jobtype.py +++ b/tests/base/job/test_jobtype.py @@ -4,9 +4,9 @@ class TestJobType(unittest.TestCase): def test_static_isinstance(self): - self.assertTrue(static_isinstance(obj=list(), obj_type=['builtins.list', 'builtins.object'])) - self.assertTrue(static_isinstance(obj=list(), obj_type='builtins.list')) - self.assertTrue(static_isinstance(obj=list().__class__, obj_type='builtins.list')) + self.assertTrue(static_isinstance(obj=list(), obj_type=['builtins.list', '__builtin__.list'])) + self.assertTrue(any[static_isinstance(obj=list(), obj_type='builtins.list'), + static_isinstance(obj=list(), obj_type='__builtin__.list')]) self.assertRaises(TypeError, static_isinstance, list(), 1) From b6058a4f7a3599f2e6432ebb59d56e037dfbe8c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Jan=C3=9Fen?= Date: Wed, 6 Feb 2019 10:21:06 +0100 Subject: [PATCH 10/10] fixes --- tests/base/job/test_jobtype.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/base/job/test_jobtype.py b/tests/base/job/test_jobtype.py index 5a67d21cc..295fe44a3 100644 --- a/tests/base/job/test_jobtype.py +++ b/tests/base/job/test_jobtype.py @@ -5,8 +5,8 @@ class TestJobType(unittest.TestCase): def test_static_isinstance(self): self.assertTrue(static_isinstance(obj=list(), obj_type=['builtins.list', '__builtin__.list'])) - self.assertTrue(any[static_isinstance(obj=list(), obj_type='builtins.list'), - static_isinstance(obj=list(), obj_type='__builtin__.list')]) + self.assertTrue(any([static_isinstance(obj=list(), obj_type='builtins.list'), + static_isinstance(obj=list(), obj_type='__builtin__.list')])) self.assertRaises(TypeError, static_isinstance, list(), 1)