salabim 25.0.2__py3-none-any.whl → 25.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- salabim/salabim.py +89 -32
- {salabim-25.0.2.dist-info → salabim-25.0.5.dist-info}/METADATA +1 -1
- {salabim-25.0.2.dist-info → salabim-25.0.5.dist-info}/RECORD +5 -5
- {salabim-25.0.2.dist-info → salabim-25.0.5.dist-info}/WHEEL +1 -1
- {salabim-25.0.2.dist-info → salabim-25.0.5.dist-info}/top_level.txt +0 -0
salabim/salabim.py
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# _ _ _ ____ ____ ___ ____
|
2
|
-
# ___ __ _ | | __ _ | |__ (_) _ __ ___ |___ \ | ___| / _ \ |___
|
3
|
-
# / __| / _` || | / _` || '_ \ | || '_ ` _ \ __) ||___ \ | | | |
|
4
|
-
# \__ \| (_| || || (_| || |_) || || | | | | | / __/ ___) | _ | |_| | _
|
5
|
-
# |___/ \__,_||_| \__,_||_.__/ |_||_| |_| |_| |_____||____/ (_) \___/ (_)|
|
2
|
+
# ___ __ _ | | __ _ | |__ (_) _ __ ___ |___ \ | ___| / _ \ | ___|
|
3
|
+
# / __| / _` || | / _` || '_ \ | || '_ ` _ \ __) ||___ \ | | | | |___ \
|
4
|
+
# \__ \| (_| || || (_| || |_) || || | | | | | / __/ ___) | _ | |_| | _ ___) |
|
5
|
+
# |___/ \__,_||_| \__,_||_.__/ |_||_| |_| |_| |_____||____/ (_) \___/ (_)|____/
|
6
6
|
# discrete event simulation
|
7
7
|
#
|
8
8
|
# see www.salabim.org for more information, the documentation and license information
|
9
9
|
|
10
|
-
__version__ = "25.0.
|
10
|
+
__version__ = "25.0.5"
|
11
11
|
import heapq
|
12
12
|
import random
|
13
13
|
import time
|
@@ -42,7 +42,7 @@ import urllib.error
|
|
42
42
|
import base64
|
43
43
|
import zipfile
|
44
44
|
from pathlib import Path
|
45
|
-
|
45
|
+
|
46
46
|
|
47
47
|
from typing import Any, Union, Iterable, Tuple, List, Callable, TextIO, Dict, Set, Type, Hashable, Optional
|
48
48
|
|
@@ -99,7 +99,8 @@ _ANSI_to_rgb = {
|
|
99
99
|
"\033[0m": (),
|
100
100
|
}
|
101
101
|
|
102
|
-
ANSI=types.SimpleNamespace(**_color_name_to_ANSI)
|
102
|
+
ANSI = types.SimpleNamespace(**_color_name_to_ANSI)
|
103
|
+
|
103
104
|
|
104
105
|
def a_log(*args):
|
105
106
|
if not hasattr(a_log, "a_logfile_name"):
|
@@ -484,10 +485,10 @@ class Monitor:
|
|
484
485
|
fill: Iterable = None,
|
485
486
|
stats_only: bool = False,
|
486
487
|
env: "Environment" = None,
|
487
|
-
*args,
|
488
488
|
**kwargs,
|
489
489
|
):
|
490
490
|
self.env = _set_env(env)
|
491
|
+
_check_overlapping_parameters(self, "__init__", "setup")
|
491
492
|
|
492
493
|
if isinstance(self.env, Environment):
|
493
494
|
_set_name(name, self.env._nameserializeMonitor, self)
|
@@ -532,7 +533,7 @@ class Monitor:
|
|
532
533
|
self._x.extend(fill)
|
533
534
|
self._t.extend(len(fill) * [self.env._now])
|
534
535
|
|
535
|
-
self.setup(
|
536
|
+
self.setup(**kwargs)
|
536
537
|
|
537
538
|
def __eq__(self, other):
|
538
539
|
if isinstance(other, Monitor):
|
@@ -4356,8 +4357,9 @@ class Queue:
|
|
4356
4357
|
if omitted, default_env will be used
|
4357
4358
|
"""
|
4358
4359
|
|
4359
|
-
def __init__(self, name: str = None, monitor: Any = True, fill: Iterable = None, capacity: float = inf, env: "Environment" = None,
|
4360
|
+
def __init__(self, name: str = None, monitor: Any = True, fill: Iterable = None, capacity: float = inf, env: "Environment" = None, **kwargs) -> None:
|
4360
4361
|
self.env = _set_env(env)
|
4362
|
+
_check_overlapping_parameters(self, "__init__", "setup")
|
4361
4363
|
|
4362
4364
|
_set_name(name, self.env._nameserializeQueue, self)
|
4363
4365
|
self._head = Qmember()
|
@@ -4390,7 +4392,7 @@ class Queue:
|
|
4390
4392
|
c.enter(self)
|
4391
4393
|
if self.env._trace:
|
4392
4394
|
self.env.print_trace("", "", self.name() + " create")
|
4393
|
-
self.setup(
|
4395
|
+
self.setup(**kwargs)
|
4394
4396
|
|
4395
4397
|
def setup(self) -> None:
|
4396
4398
|
"""
|
@@ -5826,7 +5828,7 @@ class Store(Queue):
|
|
5826
5828
|
for store in c._from_stores:
|
5827
5829
|
c.leave(store._from_store_requesters)
|
5828
5830
|
with self.env.suppress_trace():
|
5829
|
-
|
5831
|
+
self.remove(item)
|
5830
5832
|
c._from_stores = []
|
5831
5833
|
c._from_store_item = item
|
5832
5834
|
c._from_store_store = self
|
@@ -5896,6 +5898,7 @@ class Animate3dBase(DynamicClass):
|
|
5896
5898
|
) -> None:
|
5897
5899
|
super().__init__()
|
5898
5900
|
self.env = _set_env(env)
|
5901
|
+
_check_overlapping_parameters(self, "__init__", "setup")
|
5899
5902
|
|
5900
5903
|
self.visible = visible
|
5901
5904
|
self.keep = keep
|
@@ -7142,6 +7145,8 @@ class Component:
|
|
7142
7145
|
):
|
7143
7146
|
self.env = _set_env(env)
|
7144
7147
|
|
7148
|
+
_check_overlapping_parameters(self, "__init__", "setup")
|
7149
|
+
|
7145
7150
|
_set_name(name, self.env._nameserializeComponent, self)
|
7146
7151
|
self._qmembers = {}
|
7147
7152
|
self._process = None
|
@@ -7196,9 +7201,22 @@ class Component:
|
|
7196
7201
|
else:
|
7197
7202
|
self.env.print_trace("", "", self.name() + " create data component", self._modetxt())
|
7198
7203
|
else:
|
7204
|
+
_check_overlapping_parameters(self, "__init__", "process")
|
7205
|
+
_check_overlapping_parameters(self, "setup", "process")
|
7206
|
+
|
7199
7207
|
self.env.print_trace("", "", self.name() + " create", self._modetxt())
|
7200
7208
|
|
7209
|
+
process_parameters = inspect.signature(self.process).parameters
|
7210
|
+
init_parameters = inspect.signature(self.__init__).parameters
|
7211
|
+
if process_parameters:
|
7212
|
+
for parameter in process_parameters:
|
7213
|
+
if parameter in init_parameters:
|
7214
|
+
raise AttributeError(
|
7215
|
+
f"{self.__class__.__name__}.process() error: parameter '{parameter}' not allowed, because it is a parameter of {self.__class__.__name__}.__init__()"
|
7216
|
+
)
|
7217
|
+
|
7201
7218
|
kwargs_p = {}
|
7219
|
+
|
7202
7220
|
if kwargs:
|
7203
7221
|
parameters = inspect.signature(p).parameters
|
7204
7222
|
|
@@ -7254,6 +7272,7 @@ by adding at the end:
|
|
7254
7272
|
self.status._value = scheduled
|
7255
7273
|
if self.env._yieldless:
|
7256
7274
|
self._glet = greenlet.greenlet(lambda: self._process(**kwargs_p), parent=self.env._glet)
|
7275
|
+
self.env.glets.append(self._glet)
|
7257
7276
|
self._reschedule(scheduled_time, priority, urgent, "activate", cap_now, extra=extra)
|
7258
7277
|
self.setup(**kwargs)
|
7259
7278
|
|
@@ -7493,14 +7512,13 @@ by adding at the end:
|
|
7493
7512
|
return return_or_print(result, as_str, file)
|
7494
7513
|
|
7495
7514
|
def _push(self, t, priority, urgent, return_value=None, switch=True):
|
7496
|
-
|
7497
|
-
|
7498
|
-
|
7499
|
-
|
7500
|
-
|
7501
|
-
|
7502
|
-
|
7503
|
-
heapq.heappush(self.env._event_list, (t, priority, seq, self, return_value))
|
7515
|
+
self.env._seq += 1
|
7516
|
+
if urgent:
|
7517
|
+
seq = -self.env._seq
|
7518
|
+
else:
|
7519
|
+
seq = self.env._seq
|
7520
|
+
self._on_event_list = True
|
7521
|
+
heapq.heappush(self.env._event_list, (t, priority, seq, self, return_value))
|
7504
7522
|
if self.env._yieldless:
|
7505
7523
|
if self is self.env._current_component:
|
7506
7524
|
self.env._glet.switch()
|
@@ -7928,6 +7946,7 @@ by adding:
|
|
7928
7946
|
lineno = self.lineno_txt(add_at=True)
|
7929
7947
|
self.env.print_trace("", "", self.name() + " passivate", merge_blanks(lineno, self._modetxt()))
|
7930
7948
|
self.status._value = passive
|
7949
|
+
self._push(inf, 0, False, None)
|
7931
7950
|
|
7932
7951
|
if self.env._yieldless:
|
7933
7952
|
if self is self.env._current_component:
|
@@ -8069,6 +8088,8 @@ by adding:
|
|
8069
8088
|
self.env.print_trace("", "", "cancel " + self.name() + " " + self._modetxt())
|
8070
8089
|
self.status._value = data
|
8071
8090
|
if self.env._yieldless:
|
8091
|
+
self._glet.throw()
|
8092
|
+
self._glet = None
|
8072
8093
|
if self is self.env._current_component:
|
8073
8094
|
self.env._glet.switch()
|
8074
8095
|
|
@@ -8618,7 +8639,7 @@ by adding:
|
|
8618
8639
|
scheduled_time = fail_at + self.env._offset
|
8619
8640
|
else:
|
8620
8641
|
raise ValueError("both fail_at and fail_delay specified")
|
8621
|
-
schedule_priority=priority
|
8642
|
+
schedule_priority = priority
|
8622
8643
|
self.set_mode(mode)
|
8623
8644
|
|
8624
8645
|
self._failed = False
|
@@ -9019,7 +9040,7 @@ by adding:
|
|
9019
9040
|
raise ValueError("both fail_at and fail_delay specified")
|
9020
9041
|
|
9021
9042
|
self.set_mode(mode)
|
9022
|
-
schedule_priority=priority
|
9043
|
+
schedule_priority = priority
|
9023
9044
|
|
9024
9045
|
self._cond = cond # add test ***
|
9025
9046
|
for state in states:
|
@@ -9222,11 +9243,10 @@ by adding:
|
|
9222
9243
|
scheduled_time = fail_at + self.env._offset
|
9223
9244
|
else:
|
9224
9245
|
raise ValueError("both fail_at and fail_delay specified")
|
9225
|
-
schedule_priority=priority
|
9246
|
+
schedule_priority = priority
|
9226
9247
|
self.set_mode(mode)
|
9227
9248
|
|
9228
9249
|
for arg in args:
|
9229
|
-
|
9230
9250
|
value = True
|
9231
9251
|
priority = request_priority
|
9232
9252
|
if isinstance(arg, State):
|
@@ -9262,7 +9282,6 @@ by adding:
|
|
9262
9282
|
if not self._waits:
|
9263
9283
|
raise TypeError("no states specified")
|
9264
9284
|
|
9265
|
-
|
9266
9285
|
self._remaining_duration = scheduled_time - self.env._now
|
9267
9286
|
|
9268
9287
|
self._trywait()
|
@@ -10546,9 +10565,11 @@ class Environment:
|
|
10546
10565
|
do_reset: bool = None,
|
10547
10566
|
blind_animation: bool = False,
|
10548
10567
|
yieldless: bool = None,
|
10549
|
-
*args,
|
10550
10568
|
**kwargs,
|
10551
10569
|
):
|
10570
|
+
_check_overlapping_parameters(self, "__init__", "setup")
|
10571
|
+
|
10572
|
+
self.glets = []
|
10552
10573
|
if name is None:
|
10553
10574
|
if isdefault_env:
|
10554
10575
|
name = "default environment"
|
@@ -10713,7 +10734,7 @@ class Environment:
|
|
10713
10734
|
if ap_kwargs:
|
10714
10735
|
self.animation_parameters(**ap_kwargs)
|
10715
10736
|
|
10716
|
-
self.setup(
|
10737
|
+
self.setup(**kwargs)
|
10717
10738
|
|
10718
10739
|
# ENVIRONMENT ANNOTATION START
|
10719
10740
|
# ENVIRONMENT ANNOTATION END
|
@@ -10731,6 +10752,10 @@ class Environment:
|
|
10731
10752
|
"""
|
10732
10753
|
pass
|
10733
10754
|
|
10755
|
+
def cancel_all(self):
|
10756
|
+
for t, priority, sequence, comp, return_value in self._event_list:
|
10757
|
+
comp.cancel()
|
10758
|
+
|
10734
10759
|
def serialize(self) -> int:
|
10735
10760
|
self.serial += 1
|
10736
10761
|
return self.serial
|
@@ -11203,6 +11228,8 @@ class Environment:
|
|
11203
11228
|
if self._event_list:
|
11204
11229
|
(t, priority, seq, c, return_value) = heapq.heappop(self._event_list)
|
11205
11230
|
else:
|
11231
|
+
t = inf # only events with t==inf left, so signal that we have ended
|
11232
|
+
if t == inf:
|
11206
11233
|
c = self._main
|
11207
11234
|
if self.end_on_empty_eventlist:
|
11208
11235
|
t = self.env._now
|
@@ -23495,8 +23522,10 @@ class State:
|
|
23495
23522
|
if omitted, default_env is used
|
23496
23523
|
"""
|
23497
23524
|
|
23498
|
-
def __init__(self, name: str = None, value: Any = False, type: str = "any", monitor: bool = True, env: "Environment" = None,
|
23525
|
+
def __init__(self, name: str = None, value: Any = False, type: str = "any", monitor: bool = True, env: "Environment" = None, **kwargs):
|
23499
23526
|
self.env = _set_env(env)
|
23527
|
+
_check_overlapping_parameters(self, "__init__", "setup")
|
23528
|
+
|
23500
23529
|
_set_name(name, self.env._nameserializeState, self)
|
23501
23530
|
self._value = value
|
23502
23531
|
with self.env.suppress_trace():
|
@@ -23505,7 +23534,7 @@ class State:
|
|
23505
23534
|
self.value = _StateMonitor(parent=self, name="Value of " + self.name(), level=True, initial_tally=value, monitor=monitor, type=type, env=self.env)
|
23506
23535
|
if self.env._trace:
|
23507
23536
|
self.env.print_trace("", "", self.name() + " create", "value = " + repr(self._value))
|
23508
|
-
self.setup(
|
23537
|
+
self.setup(**kwargs)
|
23509
23538
|
|
23510
23539
|
def setup(self) -> None:
|
23511
23540
|
"""
|
@@ -23968,10 +23997,11 @@ class Resource:
|
|
23968
23997
|
honor_only_highest_priority: bool = False,
|
23969
23998
|
monitor: bool = True,
|
23970
23999
|
env: "Environment" = None,
|
23971
|
-
*args,
|
23972
24000
|
**kwargs,
|
23973
24001
|
):
|
23974
24002
|
self.env = _set_env(env)
|
24003
|
+
_check_overlapping_parameters(self, "__init__", "setup")
|
24004
|
+
|
23975
24005
|
if initial_claimed_quantity != 0:
|
23976
24006
|
if not anonymous:
|
23977
24007
|
raise ValueError("initial_claimed_quantity != 0 only allowed for anonymous resources")
|
@@ -24006,7 +24036,7 @@ class Resource:
|
|
24006
24036
|
self.occupancy = _SystemMonitor("Occupancy of " + self.name(), level=True, initial_tally=0, monitor=monitor, type="float", env=self.env)
|
24007
24037
|
if self.env._trace:
|
24008
24038
|
self.env.print_trace("", "", self.name() + " create", "capacity=" + str(self._capacity) + (" anonymous" if self._anonymous else ""))
|
24009
|
-
self.setup(
|
24039
|
+
self.setup(**kwargs)
|
24010
24040
|
|
24011
24041
|
def ispreemptive(self) -> bool:
|
24012
24042
|
"""
|
@@ -25090,6 +25120,28 @@ def _set_name(name, _nameserialize, object):
|
|
25090
25120
|
object._name = name
|
25091
25121
|
|
25092
25122
|
|
25123
|
+
def _check_overlapping_parameters(obj, method_name0, method_name1):
|
25124
|
+
"""
|
25125
|
+
this function is a helper to see whether __init__, setup and process parameters overlap
|
25126
|
+
|
25127
|
+
Parameters
|
25128
|
+
----------
|
25129
|
+
obj : object
|
25130
|
+
object to be checked (usually called with self)
|
25131
|
+
|
25132
|
+
method_name0 : str
|
25133
|
+
name of the first method to be tested
|
25134
|
+
|
25135
|
+
method_name1 : str
|
25136
|
+
name of the second method to be tested
|
25137
|
+
"""
|
25138
|
+
overlapping_parameters = set(inspect.signature(getattr(obj, method_name0)).parameters) & set(inspect.signature(getattr(obj, method_name1)).parameters)
|
25139
|
+
if overlapping_parameters:
|
25140
|
+
raise TypeError(
|
25141
|
+
f"{obj.__class__.__name__}.{method_name1}() error: parameter '{list(overlapping_parameters)[0]}' not allowed, because it is also a parameter of {obj.__class__.__name__}.{method_name0}()"
|
25142
|
+
)
|
25143
|
+
|
25144
|
+
|
25093
25145
|
@functools.lru_cache()
|
25094
25146
|
def _screen_dimensions():
|
25095
25147
|
if PythonInExcel or AnacondaCode:
|
@@ -27821,7 +27873,12 @@ def set_environment_aliases():
|
|
27821
27873
|
return # do not set when using Sphinx build!
|
27822
27874
|
|
27823
27875
|
for name, obj in list(globals().items()):
|
27824
|
-
if (
|
27876
|
+
if (
|
27877
|
+
(not name.startswith("_") or name in ("_Trajectory", "_Distribution"))
|
27878
|
+
and name != "yieldless"
|
27879
|
+
and name != "Environment"
|
27880
|
+
and not hasattr(Environment, name)
|
27881
|
+
):
|
27825
27882
|
if inspect.isclass(obj) and obj.__module__ == Environment.__module__:
|
27826
27883
|
if issubclass(obj, Exception):
|
27827
27884
|
exec(f"Environment.{name}={name}")
|
@@ -3,8 +3,8 @@ salabim/LICENSE.txt,sha256=eTPlcDJz4G0096Qv-wfMjm1Wxbd4ilDlsYg5rN4HjWQ,1106
|
|
3
3
|
salabim/__init__.py,sha256=r7qPLvlmX0dkZDyjuTo8Jo3ex3sD1L4pmK6K5ib9vyw,56
|
4
4
|
salabim/calibri.ttf,sha256=RWpf8Uo31RfvGGNaSt9-2sXSuN87AVE_NFMRsV3LhBk,1330156
|
5
5
|
salabim/mplus-1m-regular.ttf,sha256=EuFHr90BJjuAn_r5MleJFN-WfkeWJ4tf7DweI5zr8tU,289812
|
6
|
-
salabim/salabim.py,sha256=
|
7
|
-
salabim-25.0.
|
8
|
-
salabim-25.0.
|
9
|
-
salabim-25.0.
|
10
|
-
salabim-25.0.
|
6
|
+
salabim/salabim.py,sha256=8JPEhiyjRY0_wPsfbcyDbMXciSKdCSzM3bbNOCeFYmc,1126040
|
7
|
+
salabim-25.0.5.dist-info/METADATA,sha256=Ia0_uZ1GmfCXq8sOlrLmwF9ART30RrA8jTYVrpIP7zc,3457
|
8
|
+
salabim-25.0.5.dist-info/WHEEL,sha256=52BFRY2Up02UkjOa29eZOS2VxUrpPORXg1pkohGGUS8,91
|
9
|
+
salabim-25.0.5.dist-info/top_level.txt,sha256=UE6zVlbi3F6T5ma1a_5TrojMaF21GYKDt9svvm0U4cQ,8
|
10
|
+
salabim-25.0.5.dist-info/RECORD,,
|
File without changes
|