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 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.2"
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(*args, **kwargs)
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, *args, **kwargs) -> 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(*args, **kwargs)
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
- item = self.pop(0)
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
- if t != inf:
7497
- self.env._seq += 1
7498
- if urgent:
7499
- seq = -self.env._seq
7500
- else:
7501
- seq = self.env._seq
7502
- self._on_event_list = True
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(*args, **kwargs)
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, *args, **kwargs):
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(*args, **kwargs)
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(*args, **kwargs)
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 (not name.startswith("_") or name in ("_Trajectory", "_Distribution")) and name != "yieldless" and name != "Environment" and not hasattr(Environment,name):
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}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: salabim
3
- Version: 25.0.2
3
+ Version: 25.0.5
4
4
  Summary: salabim - discrete event simulation in Python
5
5
  Author-email: Ruud van der Ham <rt.van.der.ham@gmail.com>
6
6
  Project-URL: Homepage, https://salabim.org
@@ -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=HZGoHWng0YaeCS0BkGPAkavGHgMdw3JfQB6AlYLkRLA,1123721
7
- salabim-25.0.2.dist-info/METADATA,sha256=0QGrK9jj-tPPgRPqfnsuNBwjueyMGGr5PL5ZGe3t53o,3457
8
- salabim-25.0.2.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
9
- salabim-25.0.2.dist-info/top_level.txt,sha256=UE6zVlbi3F6T5ma1a_5TrojMaF21GYKDt9svvm0U4cQ,8
10
- salabim-25.0.2.dist-info/RECORD,,
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,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.8.0)
2
+ Generator: setuptools (76.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5