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
11 changes: 6 additions & 5 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -32,11 +38,6 @@
assert results[0]["SubjectID"] == "S001"
assert results[0]["SubjectHeight"] == 1.8
```
* {meth}`results.to_dataframe()
<anypytools.tools.AnyPyProcessOutput.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

Expand Down
2 changes: 1 addition & 1 deletion anypytools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"NORMAL_PRIORITY_CLASS",
]

__version__ = "1.19.2"
__version__ = "1.20.0"


def print_versions():
Expand Down
28 changes: 21 additions & 7 deletions anypytools/abcutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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):
Expand All @@ -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.

Expand Down Expand Up @@ -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
Expand All @@ -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.")
Expand Down Expand Up @@ -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):
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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))

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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()
4 changes: 2 additions & 2 deletions pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "*" }
Expand Down