Skip to content

Commit aa196e7

Browse files
authored
Update and simplify documentation (#128)
* Update documenation to new theme * Support stange output variable names * Refactor `to_dataframe` method to include task information option and update documentation * Update user guide, and simply as many examples as possible. * black formatting * Update dependencies * Update user guide to clarify installation and setup instructions * Expose `wraptext` function in the module's public API * Update api docs to render docstrings correctly
1 parent 362c1dd commit aa196e7

82 files changed

Lines changed: 7458 additions & 9225 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ Tests/anytest_output
2121
# pixi environments
2222
.pixi
2323

24+
docs/apidocs/*
25+
docs/user-guide/*.txt

CHANGELOG.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@
22

33
## v1.19.0
44

5+
**Changed:**
6+
* The `results.to_dataframe()` no longer returns the special `task_*` (meta data) in the output columns.
7+
To get the extra task info use `results.to_dataframe(*, include_task_info=True)`
8+
* The documentation page updated.
9+
510
**Added:**
611
* New `macro_commands.ExtendOutput()` helper macro that can add arbitrary values
712
to the results output. This allows adding values that don't need to exist as
@@ -230,7 +235,7 @@ just treated as NaN.
230235
- Fixed issue which would cauase macros to execute twice when running the GUI version of AnyBody.
231236

232237
**Added:**
233-
- Added a `interactive_mode` argument to the {class}`AnyPyProcess <anypytools.AnPyProcess>` class. Setting this argument will automaticially lauch the GUI version
238+
- Added a `interactive_mode` argument to the {class}`AnyPyProcess <anypytools.abcutils.AnyPyProcess>` class. Setting this argument will automaticially lauch the GUI version
234239
of AnyBody with the macro commands. Futher it will not automatically exit AnyBody once the macro commands has finished. This must be done manually by the user.
235240

236241

@@ -546,15 +551,15 @@ happend because empty folders (represented by "...") would become the python eli
546551

547552
**Fixed:**
548553

549-
- Fix regression in for {class}`AnyPyTools.macro_comands.SetValue_random` which caused a
554+
- Fix regression in for {py:class}`SetValue_random <anypytools.macroutils.SetValue_random>` which caused a
550555
crash when generating macros.
551556

552557
## v0.12
553558

554559
**Fixed:**
555560

556561
- Missing newlines in error output from pytest plugin.
557-
- Fix a problem where the `ignore_errors` argument to {class}`AnyPyProcess()` could
562+
- Fix a problem where the `ignore_errors` argument to {class}`anypytools.abcutils.AnyPyProcess` could
558563
not filter warnings when they were considered as errors with the `fatal_warnings`
559564
arguments.
560565

@@ -578,7 +583,7 @@ happend because empty folders (represented by "...") would become the python eli
578583
**New:**
579584

580585
- Added option to the set the priority of the macro operations.
581-
The option is an argument to {class}`AnyPyProcess()`.
586+
The option is an argument to {class}`AnyPyProcess <anypytools.abcutils.AnyPyProcess>`.
582587

583588
```python
584589
from anypytools import IDLE_PRIORITY_CLASS
@@ -593,7 +598,7 @@ happend because empty folders (represented by "...") would become the python eli
593598
- `NORMAL_PRIORITY_CLASS`
594599
- `ABOVE_NORMAL_PRIORITY_CLASS`.
595600

596-
- Added argument `fatal_warnings` to {class}`AnyPyProcess()` which
601+
- Added argument `fatal_warnings` to {class}`AnyPyProcess <anypytools.abcutils.AnyPyProcess>` which
597602
treat warnings as errors when running macros.
598603

599604
```python

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ If you use the library for publications please **cite as:**
2727
```bash
2828
pixi init
2929
pixi add anypytools
30-
pixi install
3130
```
3231

3332
This will install a virtual environment with python, anypytools and all
@@ -60,6 +59,4 @@ Please see the [Jupyter Notebook based tutorial], or check the the following for
6059
<img src="docs/_static/relax.png" alt="Don't panic" height="100px">
6160

6261

63-
[anaconda python distribution]: https://store.continuum.io/cshop/anaconda/
6462
[anybody modeling system (ams)]: http://www.anybodytech.com
65-
[jupyter notebook based tutorial]: http://nbviewer.jupyter.org/github/AnyBody-Research-Group/AnyPyTools/blob/master/docs/Tutorial/00_AnyPyTools_tutorial.ipynb

anypytools/abcutils.py

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@
5353
winepath,
5454
)
5555

56+
__all__ = [
57+
"execute_anybodycon",
58+
"AnyPyProcess",
59+
"Task",
60+
]
61+
5662
if ON_WINDOWS:
5763
from .jobpopen import JobPopen as Popen
5864
from subprocess import CREATE_NEW_PROCESS_GROUP
@@ -107,7 +113,7 @@ def stop_all(self):
107113
atexit.register(_subprocess_container.stop_all)
108114

109115

110-
def progress_print(progress, content):
116+
def _progress_print(progress, content):
111117
previous = progress.console.is_jupyter
112118
progress.console.is_jupyter = False
113119
progress.console.print(content)
@@ -133,13 +139,13 @@ def execute_anybodycon(
133139
134140
Parameters
135141
----------
136-
macro : list of str
142+
macro : list[str]
137143
List of macros strings to pass to the AnyBody Console Application
138-
logfile : file like object, optional
144+
logfile : typing.TextIO, optional
139145
An open file like object to write to pipe the output of AnyBody
140146
into. (Defaults to None, in which case it will use sys.stdout)
141147
anybodycon_path : str, optional
142-
Path to the AnyBodyConsole application. Default to None, in which
148+
Path to the AnyBodyConsole applibcation. Default to None, in which
143149
case the default installed AnyBody installation will be looked up
144150
in the Windows registry.
145151
timeout : int, optional
@@ -159,14 +165,15 @@ def execute_anybodycon(
159165
interactive_mode : bool, optional
160166
If set to True, the AnyBody Console application will be started in iteractive
161167
mode, and will not shutdown autmaticaly after running the macro. (Defaults to False)
162-
debug_mode : int
168+
debug_mode : int, optional
163169
The AMS debug mode to use. Defaults to 0 which is disabled. 1 correspond to
164170
crashdump enabled
165-
folder : the folder in which AnyBody is executed
171+
folder :
172+
the folder in which AnyBody is executed
166173
167174
Returns
168175
-------
169-
int
176+
error_code : int
170177
The return code from the AnyBody Console application.
171178
172179
"""
@@ -314,7 +321,7 @@ def execute_anybodycon(
314321
return retcode
315322

316323

317-
class _Task(object):
324+
class Task(object):
318325
"""Class for storing processing jobs.
319326
320327
Attributes:
@@ -418,7 +425,7 @@ def is_valid(output_elem):
418425
return all(k in output_elem for k in keys)
419426

420427

421-
def tasklist_summery(tasklist: List[_Task]) -> str:
428+
def _tasklist_summery(tasklist: List[Task]) -> str:
422429
out = ""
423430
unfinished_tasks = [t for t in tasklist if t.processtime <= 0]
424431
failed_tasks = [t for t in tasklist if t.has_error() and t.processtime > 0]
@@ -431,7 +438,7 @@ def tasklist_summery(tasklist: List[_Task]) -> str:
431438
return out
432439

433440

434-
def task_summery(task: _Task) -> str:
441+
def _task_summery(task: Task) -> str:
435442
if task.has_error():
436443
status = "Failed"
437444
elif task.processtime == 0:
@@ -490,7 +497,7 @@ class AnyPyProcess(object):
490497
String which will be prefixed to the generated log files. This can be used
491498
to assign a more meaningfull name to a batch of logfiles.
492499
(Defaults to None)
493-
python_env : pathlike, optional
500+
python_env : str, optional
494501
Path to a python environment/installation that the AnyBody Modeling System
495502
should use for Python Hooks. This will added the ``PYTHONHOME`` environment variable and
496503
prepended to the ``PATH`` before starting the AnyBody Console application.
@@ -739,10 +746,10 @@ def start_macro(
739746
740747
Parameters
741748
----------
742-
macrolist : list of macrocommands, optional
749+
macrolist : list, optional
743750
List of anyscript macro commands. This may also be obmitted in
744751
which case the previous macros will be re-run.
745-
folderlist : list of str, optional
752+
folderlist : list[str], optional
746753
List of folders in which to excute the macro commands. If `None` the
747754
current working directory is used. This may also be a list of
748755
tuples to specify a name to appear in the output
@@ -822,7 +829,7 @@ def start_macro(
822829
"to process"
823830
)
824831
elif isinstance(macrolist[0], collections.abc.Mapping):
825-
tasklist = list(_Task.from_output_list(macrolist))
832+
tasklist = list(Task.from_output_list(macrolist))
826833
elif isinstance(macrolist[0], list):
827834
arg_hash = format(
828835
abs(make_hash([macrolist, folderlist, search_subdirs, logfile])), "x"
@@ -832,7 +839,7 @@ def start_macro(
832839
else:
833840
self.cached_arg_hash = arg_hash
834841
tasklist = list(
835-
_Task.from_macrofolderlist(macrolist, folderlist, logfile)
842+
Task.from_macrofolderlist(macrolist, folderlist, logfile)
836843
)
837844
else:
838845
raise ValueError("Nothing to process for " + str(macrolist))
@@ -850,15 +857,15 @@ def start_macro(
850857
try:
851858
for task in self._schedule_processes(tasklist):
852859
if task.has_error() and not self.silent:
853-
progress_print(progress, task_summery(task))
860+
_progress_print(progress, _task_summery(task))
854861
progress.update(task_progress, style="red", refresh=True)
855862
progress.update(task_progress, advance=1, refresh=True)
856863
except KeyboardInterrupt:
857-
progress_print(progress, "[red]KeyboardInterrupt: User aborted[/red]")
864+
_progress_print(progress, "[red]KeyboardInterrupt: User aborted[/red]")
858865
finally:
859866
_subprocess_container.stop_all()
860867
if not self.silent:
861-
progress_print(progress, tasklist_summery(tasklist))
868+
_progress_print(progress, _tasklist_summery(tasklist))
862869

863870
self.cleanup_logfiles(tasklist)
864871
# Cache the processed tasklist for restarting later
@@ -940,9 +947,7 @@ def _worker(self, task, task_queue):
940947
task.logfile = ""
941948
task_queue.put(task)
942949

943-
def _schedule_processes(
944-
self, tasklist: List[_Task]
945-
) -> Generator[_Task, None, None]:
950+
def _schedule_processes(self, tasklist: List[Task]) -> Generator[Task, None, None]:
946951
# Make a shallow copy of the task list,
947952
# so we don't mess with the callers list.
948953
tasklist = copy.copy(tasklist)

anypytools/h5py_wrapper.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
logger = logging.getLogger("abt.anypytools")
1212

13+
__all__ = ["File", "Group", "Dataset"]
14+
1315

1416
def _follow_reftarget(elem):
1517
completename = elem.attrs["CompleteName"]

anypytools/jobpopen.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import win32process
1616
import pywintypes
1717

18+
__all__ = ["JobPopen"]
19+
1820

1921
class JobPopen(Popen):
2022
"""Start a process in a new Win32 job object.

anypytools/macroutils.py

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ def get_macro(self, index, **kwarg):
7979
8080
Returns
8181
-------
82-
string
82+
str
8383
A string with the AnyScript macro
8484
8585
"""
@@ -139,9 +139,9 @@ class SetValue(MacroCommand):
139139
140140
Parameters
141141
----------
142-
var : string
142+
var : str
143143
An AnyScript variable.
144-
value : number or list of number
144+
value : float | list[float]
145145
A value or list of values to assign to the AnyScript variable.
146146
147147
Examples
@@ -232,13 +232,13 @@ def _format_macro(self, val):
232232
class SetValue_random(SetValue):
233233
"""Create a 'Set Value' macro command from a distribution.
234234
235-
The value is connected to a distibution in scipy.stats.distributions.
235+
The value is connected to a distibution in ``scipy.stats.distributions``.
236236
237237
Parameters
238238
----------
239239
var : str
240240
An AnyScript variable.
241-
frozen_distribution : <scipy.stats.distributions.rv_frozen>
241+
frozen_distribution :
242242
A frozen distribution from scipy.stats.distributions
243243
default_lower_tail_probability : float
244244
The lower tail probability of the default value. Defaults to 0.5 which
@@ -430,11 +430,11 @@ class ExtendOutput(MacroCommand):
430430
----------
431431
var_name : str
432432
Name of the variable in output.
433-
value : any
433+
value : int | float | str | np.ndarray
434434
The value to add to the output.
435435
436-
Examples:
437-
---------
436+
Examples
437+
--------
438438
>>> ExtendOutput('MyVar', 23.5)
439439
print MyVar = 23.5;
440440
@@ -457,7 +457,16 @@ def get_macro(self, index, **kwarg):
457457
val_str = f"'{self.value}'"
458458
else:
459459
val_str = str(self.value)
460-
return f'print "{self.var_name} = {val_str};"'
460+
461+
cmd = ""
462+
if self.var_name.isidentifier():
463+
name = self.var_name
464+
else:
465+
cmd += f'print "#### ANYPYTOOLS RENAME OUTPUT: {self.var_name}"\n'
466+
name = "DUMMY"
467+
468+
cmd += f'print "{name} = {val_str};"'
469+
return cmd
461470

462471

463472
class SaveDesign(MacroCommand):
@@ -710,8 +719,7 @@ class AnyMacro(MutableSequence):
710719
>>> mg = AnyMacro(number_of_macros = 22)
711720
>>> mg.append( Load('c:/MyModel/model.main.any', defs = {}, paths = {} ) )
712721
>>> mg.append( SetValue('Main.myvar', 12.3) )
713-
>>> mg.extend( [RunOperation('Main.Study.Kinematics'),
714-
Dump('Main.Study.Output.MyVar') ] )
722+
>>> mg.extend( [RunOperation('Main.Study.Kinematics'), Dump('Main.Study.Output.MyVar') ] )
715723
>>> mg
716724
[['load "c:/MyModel/model.main.any"',
717725
'classoperation Main.myvar "Set Value" --value="12.3"',

anypytools/pytest_plugin.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,18 @@
3434
get_bm_constants,
3535
anybodycon_version,
3636
find_ammr_path,
37-
get_tag,
3837
get_ammr_version,
3938
winepath,
4039
wraptext,
4140
AMSVersion,
4241
)
4342

44-
45-
@contextlib.contextmanager
46-
def cwd(path):
47-
oldpwd = os.getcwd()
48-
os.chdir(path)
49-
try:
50-
yield
51-
finally:
52-
os.chdir(oldpwd)
43+
__all__ = [
44+
"AnyTestFile",
45+
"AnyTestItem",
46+
"AnyException",
47+
"AnyTestSession",
48+
]
5349

5450

5551
DEFAULT_ANYTEST_OUTPUT = Path.cwd() / "anytest-output"
@@ -58,7 +54,7 @@ def cwd(path):
5854
RUN_TEST_TIME_VARIABLE = "Main.RunTest.RunDurationCPUThread"
5955

6056

61-
def load_duration_supported():
57+
def _is_load_duration_supported():
6258
return AMSVersion.from_string(pytest.anytest.ams_version) >= (7, 5, 0, 10759)
6359

6460

@@ -314,7 +310,7 @@ def __init__(self, name, id, parent, any_defs, any_paths, **kwargs):
314310
macro_commands.Load(mainfile, self.any_defs, self.any_paths),
315311
]
316312

317-
if load_duration_supported():
313+
if _is_load_duration_supported():
318314
self.macro += [
319315
macro_commands.Dump(LOAD_TIME_VARIABLE),
320316
]
@@ -348,7 +344,7 @@ def __init__(self, name, id, parent, any_defs, any_paths, **kwargs):
348344
if not self.config.getoption("--only-load"):
349345
self.macro += [macro_commands.RunOperation("Main.RunTest")]
350346

351-
if load_duration_supported():
347+
if _is_load_duration_supported():
352348
self.macro += [
353349
macro_commands.Dump(RUN_TEST_TIME_VARIABLE),
354350
]
@@ -398,7 +394,7 @@ def runtest(self):
398394
self.macro, logfile=Path(self.name).with_suffix(".txt")
399395
)[0]
400396

401-
if load_duration_supported():
397+
if _is_load_duration_supported():
402398
load_time = result.get(LOAD_TIME_VARIABLE, None)
403399
if load_time is not None:
404400
self.user_properties.append(("Load time", load_time))

0 commit comments

Comments
 (0)