diff --git a/CHANGELOG.md b/CHANGELOG.md index 94c33d2..c3c4a12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # AnyPyTools Change Log +## v1.20.0 + +* Fixed a problem that prevented multiple AnyPyTools instances from running + simultaneously in the same process. Previously, other running AnyBody instances + were shut down when the first `AnyPyProcess.start_macro()` call finished. + ## v1.19.2 * Fixed missing widget information is user-guide documentation. @@ -32,11 +38,6 @@ assert results[0]["SubjectID"] == "S001" assert results[0]["SubjectHeight"] == 1.8 ``` -* {meth}`results.to_dataframe() - ` has a new argument - `exclude_task_info` which can exclude task information (variables starting - with 'task_') when exporting results to a dataframe - ## v1.18 diff --git a/anypytools/__init__.py b/anypytools/__init__.py index 4178cf1..e743d04 100644 --- a/anypytools/__init__.py +++ b/anypytools/__init__.py @@ -36,7 +36,7 @@ "NORMAL_PRIORITY_CLASS", ] -__version__ = "1.19.2" +__version__ = "1.20.0" def print_versions(): diff --git a/anypytools/abcutils.py b/anypytools/abcutils.py index 5381fc0..3baa926 100644 --- a/anypytools/abcutils.py +++ b/anypytools/abcutils.py @@ -60,7 +60,12 @@ ] if ON_WINDOWS: - from .jobpopen import JobPopen as Popen + if "ANYPYTOOLS_DEBUG_USE_PYTHON_POPEN" in os.environ: + logger.warning("Warning: Using Python's subprocess.Popen instead of JobPopen.") + from subprocess import Popen + else: + from .jobpopen import JobPopen as Popen + from subprocess import CREATE_NEW_PROCESS_GROUP else: from subprocess import Popen @@ -109,8 +114,8 @@ def stop_all(self): self._pids.clear() -_subprocess_container = _SubProcessContainer() -atexit.register(_subprocess_container.stop_all) +_global_subprocess_container = _SubProcessContainer() +atexit.register(_global_subprocess_container.stop_all) def _progress_print(progress, content): @@ -131,6 +136,7 @@ def execute_anybodycon( debug_mode=0, folder=None, interactive_mode=False, + subprocess_container=_global_subprocess_container, ): """Launch a single AnyBodyConsole applicaiton. @@ -274,7 +280,7 @@ def execute_anybodycon( proc = Popen(cmd, **kwargs) retcode = None - _subprocess_container.add(proc.pid) + subprocess_container.add(proc.pid) try: proc.wait(timeout=timeout) retcode = ctypes.c_int32(proc.returncode).value @@ -293,7 +299,7 @@ def execute_anybodycon( if ON_WINDOWS: proc._close_job_object(proc._win32_job) else: - _subprocess_container.remove(proc.pid) + subprocess_container.remove(proc.pid) if retcode == _TIMEDOUT_BY_ANYPYTOOLS: logfile.write(f"\nERROR: AnyPyTools : Timeout after {int(timeout)} sec.") @@ -607,6 +613,8 @@ def __init__( self.env = env else: self.env = None + + self._local_subprocess_container = _SubProcessContainer() logging.debug("\nAnyPyProcess initialized") def save_results(self, filename, append=False): @@ -778,7 +786,7 @@ def start_macro( """ # Handle different input types - if isinstance(macrolist, types.GeneratorType): + if isinstance(macrolist, (types.GeneratorType, tuple)): macrolist = list(macrolist) if isinstance(macrolist, AnyMacro): macrolist = macrolist.create_macros() @@ -863,7 +871,7 @@ def start_macro( except KeyboardInterrupt: _progress_print(progress, "[red]KeyboardInterrupt: User aborted[/red]") finally: - _subprocess_container.stop_all() + self._local_subprocess_container.stop_all() if not self.silent: _progress_print(progress, _tasklist_summery(tasklist)) @@ -918,6 +926,7 @@ def _worker(self, task, task_queue): debug_mode=self.debug_mode, folder=task.folder, interactive_mode=self.interactive_mode, + subprocess_container=self._local_subprocess_container, ) try: task.retcode = execute_anybodycon(**exe_args) @@ -997,3 +1006,8 @@ def cleanup_logfiles(self, tasklist): silentremove(macrofile) except OSError as e: logger.debug(f"Could not remove: {macrofile} {e}") + + def __del__(self): + """Destructor to clean up any remaining subprocesses.""" + if hasattr(self, "_local_subprocess_container"): + self._local_subprocess_container.stop_all() diff --git a/pixi.lock b/pixi.lock index f970c13..dfc9995 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1548,7 +1548,7 @@ packages: timestamp: 1758634638734 - conda: . name: anypytools - version: 1.19.2 + version: 1.20.0 build: pyh4616a5c_0 subdir: noarch depends: @@ -1566,7 +1566,7 @@ packages: - pywin32 license: MIT input: - hash: 7e2d0d0a7d3047761d10a95adebb4c0fcb16d6bf9d24ce308e404018832af082 + hash: 9fa6ba0badfc0ba8f381d093d418ecf329742d29ac1f91dbaf351feb6402988f globs: - pyproject.toml - conda: https://prefix.dev/conda-forge/win-64/aom-3.9.1-he0c23c2_0.conda diff --git a/pixi.toml b/pixi.toml index 9dba32c..56dcb32 100644 --- a/pixi.toml +++ b/pixi.toml @@ -10,7 +10,7 @@ anypytools = {path= "."} [package] name = "anypytools" -version="1.19.2" +version="1.20.0" [package.build] backend = { name = "pixi-build-python", version = "*" }