salabim 25.0.9.post2__py3-none-any.whl → 25.0.9.post4__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
@@ -46,20 +46,15 @@ from pathlib import Path
46
46
 
47
47
  from typing import Any, Union, Iterable, Tuple, List, Callable, TextIO, Dict, Set, Type, Hashable, Optional
48
48
 
49
- # module = salabim # for PythonInExcel runner
50
-
51
49
  dataframe = None # to please PyLance
52
50
 
53
51
  ColorType = Union[str, Iterable[float]]
54
52
 
55
53
  Pythonista = sys.platform == "ios"
56
54
  Windows = sys.platform.startswith("win")
57
- PyDroid = sys.platform == "linux" and any("pydroid" in v for v in os.environ.values())
58
55
  PyPy = platform.python_implementation() == "PyPy"
59
56
  Chromebook = "penguin" in platform.uname()
60
- #Xlwings="xlwings" in sys.modules
61
- Xlwings=sys.platform=="emscripten"
62
- Embedded = False # (not ("__file__" in globals())) or ((sys.platform == "emscripten") and not Xlwings) # Python In Excel or pyoide (AnacondaCode or xlwings lite)
57
+ Xlwings = "xlwings" in sys.modules
63
58
 
64
59
  _color_name_to_ANSI = dict(
65
60
  dark_black="\033[0;30m",
@@ -115,71 +110,6 @@ def a_log(*args):
115
110
 
116
111
  class g: ...
117
112
 
118
-
119
- if Embedded:
120
- _pie_result = []
121
-
122
- def pie_result():
123
- return _pie_result
124
-
125
- class b64_file_handler(io.IOBase):
126
- """
127
- special purpose file handler for Python in Excel
128
-
129
- Parameters
130
- ----------
131
- name : str
132
- name of file
133
-
134
- result : list
135
- b64 information will be added as string(s)
136
-
137
- blocksize : int
138
- b64 blocksize (default: 30000)
139
-
140
- mode : str
141
- if 't' (default): open for test
142
- if 'b': open for binary
143
-
144
- Note
145
- ----
146
- can be used as a file or in a context manager
147
- """
148
-
149
- def __init__(self, name, result, blocksize=30000, mode="t"):
150
- self._name = name
151
- self._result = result
152
- self._blocksize = blocksize
153
- if mode not in ("t", "b"):
154
- raise ValueError(f"wrong mode ({mode})")
155
- self._mode = mode
156
- self._buffer = []
157
-
158
- def __enter__(self):
159
- return self
160
-
161
- def __exit__(self, *args):
162
- self.close()
163
-
164
- def write(self, s):
165
- self._buffer.append(s)
166
-
167
- def close(self):
168
- if self._mode == "b":
169
- b = b"".join(self._buffer)
170
- else:
171
- b = "".join(self._buffer).encode("utf-8")
172
- n = self._blocksize
173
- b64 = base64.b64encode(b).decode("utf-8")
174
- self._result.append(f"<file name={self._name}>")
175
- while b64:
176
- b64_n = b64[:n]
177
- self._result.append(b64_n)
178
- b64 = b64[n:]
179
- self._result.append("</file>")
180
- super().close()
181
-
182
-
183
113
  if Pythonista:
184
114
  try:
185
115
  import scene # type: ignore
@@ -191,7 +121,7 @@ if Pythonista:
191
121
  inf = float("inf")
192
122
  nan = float("nan")
193
123
 
194
- if Pythonista or Embedded or Xlwings:
124
+ if Pythonista or Xlwings:
195
125
  _yieldless = False
196
126
  else:
197
127
  _yieldless = True
@@ -231,11 +161,9 @@ def yieldless(value: bool = None) -> bool:
231
161
  if value is not None:
232
162
  if value:
233
163
  if Pythonista:
234
- raise ValueError('yiedless mode is not allowed under Pythonista')
235
- if Embedded:
236
- raise ValueError('yiedless mode is not allowed under Python in Excel or Anaconda Code')
164
+ raise ValueError("yiedless mode is not allowed under Pythonista")
237
165
  if Xlwings:
238
- raise ValueError('yiedless mode is not allowed under xlwings lite')
166
+ raise ValueError("yiedless mode is not allowed under xlwings lite")
239
167
  _yieldless = value
240
168
  return _yieldless
241
169
 
@@ -7209,8 +7137,8 @@ class Component:
7209
7137
  else:
7210
7138
  self.env.print_trace("", "", self.name() + " create data component", self._modetxt())
7211
7139
  else:
7212
- _check_overlapping_parameters(self, "__init__", process_name,process=p)
7213
- _check_overlapping_parameters(self, "setup", process_name,process=p)
7140
+ _check_overlapping_parameters(self, "__init__", process_name, process=p)
7141
+ _check_overlapping_parameters(self, "setup", process_name, process=p)
7214
7142
 
7215
7143
  self.env.print_trace("", "", self.name() + " create", self._modetxt())
7216
7144
 
@@ -7510,7 +7438,7 @@ by adding at the end:
7510
7438
  return return_or_print(result, as_str, file)
7511
7439
 
7512
7440
  def _push(self, t, priority, urgent, return_value=None, switch=True):
7513
- if t!=inf:
7441
+ if t != inf:
7514
7442
  self.env._seq += 1
7515
7443
  if urgent:
7516
7444
  seq = -self.env._seq
@@ -10656,22 +10584,19 @@ class Environment:
10656
10584
  self.stopped = False
10657
10585
  self._paused = False
10658
10586
  self.last_s0 = ""
10659
- if Embedded or Xlwings:
10587
+ if Xlwings:
10660
10588
  if blind_animation is None:
10661
- blind_animation=True
10589
+ blind_animation = True
10662
10590
  if not blind_animation:
10663
10591
  raise ValueError("blind_animation may not be False under xlwings lite")
10664
10592
  else:
10665
10593
  if blind_animation is None:
10666
- blind_animation=False
10594
+ blind_animation = False
10667
10595
  self._blind_animation = blind_animation
10668
10596
 
10669
10597
  if self._blind_animation:
10670
10598
  with self.suppress_trace():
10671
10599
  self._blind_video_maker = _BlindVideoMaker(process="", suppress_trace=True)
10672
- if PyDroid:
10673
- if g.tkinter_loaded == "?":
10674
- g.tkinter_loaded = "tkinter" in sys.modules
10675
10600
 
10676
10601
  if Pythonista:
10677
10602
  self._width, self._height = ui.get_screen_size()
@@ -11530,8 +11455,6 @@ class Environment:
11530
11455
 
11531
11456
  If no codec is given, MJPG will be used for .avi files, otherwise .mp4v
11532
11457
 
11533
- Under PyDroid only .avi files are supported.
11534
-
11535
11458
  video_repeat : int
11536
11459
  number of times animated gif or png should be repeated
11537
11460
 
@@ -11853,8 +11776,6 @@ class Environment:
11853
11776
  self._video_name = self._video_name[:-5] # get rid of codec
11854
11777
  else:
11855
11778
  codec = "MJPG" if extension.lower() == ".avi" else "mp4v"
11856
- if PyDroid and extension.lower() != ".avi":
11857
- raise ValueError("PyDroid can only produce .avi videos, not " + extension)
11858
11779
  can_video(try_only=False)
11859
11780
  fourcc = cv2.VideoWriter_fourcc(*codec)
11860
11781
  if video_path.is_file():
@@ -11958,59 +11879,34 @@ class Environment:
11958
11879
  if self._video_pingpong:
11959
11880
  self._images.extend(self._images[::-1])
11960
11881
  if self._video_repeat == 1: # in case of repeat == 1, loop should not be specified (otherwise, it might show twice)
11961
- if Embedded:
11962
- with b64_file_handler(self._video_name, mode="b", result=_pie_result) as f:
11882
+ for _ in range(2): # normally runs only once
11883
+ try:
11963
11884
  self._images[0].save(
11964
- f,
11885
+ self._video_name,
11965
11886
  disposal=2,
11966
11887
  save_all=True,
11967
11888
  append_images=self._images[1:],
11968
11889
  duration=round(1000 / self._real_fps),
11969
11890
  optimize=False,
11970
- format="GIF",
11971
11891
  )
11972
- else:
11973
- for _ in range(2): # normally runs only once
11974
- try:
11975
- self._images[0].save(
11976
- self._video_name,
11977
- disposal=2,
11978
- save_all=True,
11979
- append_images=self._images[1:],
11980
- duration=round(1000 / self._real_fps),
11981
- optimize=False,
11982
- )
11983
- break
11984
- except ValueError: # prevent bug in Python 3.13
11985
- self._images = [image.convert("RGB") for image in self._images]
11892
+ break
11893
+ except ValueError: # prevent bug in Python 3.13
11894
+ self._images = [image.convert("RGB") for image in self._images]
11986
11895
 
11987
11896
  else:
11988
- if Embedded:
11989
- with b64_file_handler(self._video_name, mode="b", result=_pie_result) as f:
11897
+ for _ in range(2): # normally runs only once
11898
+ try:
11990
11899
  self._images[0].save(
11991
- f,
11900
+ self._video_name,
11992
11901
  disposal=2,
11993
11902
  save_all=True,
11994
11903
  append_images=self._images[1:],
11995
11904
  loop=self._video_repeat,
11996
11905
  duration=round(1000 / self._real_fps),
11997
11906
  optimize=False,
11998
- format="GIF",
11999
11907
  )
12000
- else:
12001
- for _ in range(2): # normally runs only once
12002
- try:
12003
- self._images[0].save(
12004
- self._video_name,
12005
- disposal=2,
12006
- save_all=True,
12007
- append_images=self._images[1:],
12008
- loop=self._video_repeat,
12009
- duration=round(1000 / self._real_fps),
12010
- optimize=False,
12011
- )
12012
- except ValueError: # prevent bug in Python 3.13
12013
- self._images = [image.convert("RGB") for image in self._images]
11908
+ except ValueError: # prevent bug in Python 3.13
11909
+ self._images = [image.convert("RGB") for image in self._images]
12014
11910
 
12015
11911
  del self._images
12016
11912
  elif self._video_out == "png":
@@ -13602,13 +13498,8 @@ class Environment:
13602
13498
  mode = "RGB"
13603
13499
  else:
13604
13500
  raise ValueError("extension " + extension + " not supported")
13605
- if Embedded:
13606
- with b64_file_handler(str(filename), mode="b", result=_pie_result) as f:
13607
- format = "jpeg" if extension == ".jpg" else extension[1:]
13608
- self._capture_image(mode, video_mode).save(f, format=format)
13609
- else:
13610
- filename_path.parent.mkdir(parents=True, exist_ok=True)
13611
- self._capture_image(mode, video_mode).save(str(filename))
13501
+ filename_path.parent.mkdir(parents=True, exist_ok=True)
13502
+ self._capture_image(mode, video_mode).save(str(filename))
13612
13503
 
13613
13504
  def modelname_width(self):
13614
13505
  if Environment.cached_modelname_width[0] != self._modelname:
@@ -14619,16 +14510,14 @@ class Environment:
14619
14510
  note that the header is only printed if trace=True
14620
14511
  """
14621
14512
  len_s1 = len(self.time_to_str(0))
14622
- self.print_trace((len_s1 - 4) * " " + "time", "current component", "action", "information", "" if (Embedded) else "line#")
14623
- self.print_trace(len_s1 * "-", 20 * "-", 35 * "-", 48 * "-", "" if (Embedded) else 6 * "-")
14513
+ self.print_trace((len_s1 - 4) * " " + "time", "current component", "action", "information", "line#")
14514
+ self.print_trace(len_s1 * "-", 20 * "-", 35 * "-", 48 * "-", 6 * "-")
14624
14515
  for ref in range(len(self._source_files)):
14625
14516
  for fullfilename, iref in self._source_files.items():
14626
14517
  if ref == iref:
14627
14518
  self._print_legend(iref)
14628
14519
 
14629
14520
  def _print_legend(self, ref):
14630
- if Embedded:
14631
- return
14632
14521
  if ref:
14633
14522
  s = "line numbers prefixed by " + chr(ord("A") + ref - 1) + " refer to"
14634
14523
  else:
@@ -14645,8 +14534,6 @@ class Environment:
14645
14534
  return self.filename_lineno_to_str(frameinfo.filename, frameinfo.lineno)
14646
14535
 
14647
14536
  def filename_lineno_to_str(self, filename, lineno):
14648
- if Embedded:
14649
- return "n/a"
14650
14537
  if Path(filename).name == Path(__file__).name: # internal salabim address
14651
14538
  return "n/a"
14652
14539
  ref = self._source_files.get(filename)
@@ -25116,7 +25003,7 @@ def _set_name(name, _nameserialize, object):
25116
25003
  object._name = name
25117
25004
 
25118
25005
 
25119
- def _check_overlapping_parameters(obj, method_name0, method_name1,process=None):
25006
+ def _check_overlapping_parameters(obj, method_name0, method_name1, process=None):
25120
25007
  """
25121
25008
  this function is a helper to see whether __init__, setup and process parameters overlap
25122
25009
 
@@ -25134,12 +25021,12 @@ def _check_overlapping_parameters(obj, method_name0, method_name1,process=None):
25134
25021
  process: method
25135
25022
  used for process check: should be the process methoc
25136
25023
  """
25137
- method0=getattr(obj, method_name0)
25024
+ method0 = getattr(obj, method_name0)
25138
25025
 
25139
25026
  if process is None:
25140
- method1=getattr(obj, method_name1)
25027
+ method1 = getattr(obj, method_name1)
25141
25028
  else:
25142
- method1=process
25029
+ method1 = process
25143
25030
 
25144
25031
  overlapping_parameters = set(inspect.signature(method0).parameters) & set(inspect.signature(method1).parameters)
25145
25032
  if overlapping_parameters:
@@ -25150,7 +25037,7 @@ def _check_overlapping_parameters(obj, method_name0, method_name1,process=None):
25150
25037
 
25151
25038
  @functools.lru_cache()
25152
25039
  def _screen_dimensions():
25153
- if Embedded or Xlwings:
25040
+ if Xlwings:
25154
25041
  return 1024, 768
25155
25042
  if Pythonista:
25156
25043
  screen_width, screen_height = ui.get_screen_size()
@@ -27178,7 +27065,7 @@ def _std_fonts():
27178
27065
 
27179
27066
 
27180
27067
  def fonts():
27181
- if Embedded or Xlwings:
27068
+ if Xlwings:
27182
27069
  return []
27183
27070
  if not hasattr(fonts, "font_list"):
27184
27071
  fonts.font_list = []
@@ -27451,7 +27338,7 @@ def can_animate(try_only: bool = True) -> bool:
27451
27338
  except ImportError:
27452
27339
  ImageGrab = None
27453
27340
 
27454
- if not Pythonista and not (Embedded or Xlwings):
27341
+ if not Pythonista and not Xlwings:
27455
27342
  from PIL import ImageTk
27456
27343
  except ImportError:
27457
27344
  if try_only:
@@ -27460,12 +27347,7 @@ def can_animate(try_only: bool = True) -> bool:
27460
27347
 
27461
27348
  g.dummy_image = Image.new("RGBA", (1, 1), (0, 0, 0, 0))
27462
27349
 
27463
- if not Pythonista and not (Embedded or Xlwings):
27464
- if PyDroid:
27465
- if not g.tkinter_loaded:
27466
- if try_only:
27467
- return False
27468
- raise ImportError("PyDroid animation requires that the main program imports tkinter")
27350
+ if not Pythonista and not Xlwings:
27469
27351
  try:
27470
27352
  import tkinter
27471
27353
  import tkinter.font
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: salabim
3
- Version: 25.0.9.post2
3
+ Version: 25.0.9.post4
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=wNIHiSS93kWglqmU6jy6KQMZCLAUoaofvqsPUP_PvPE,1125989
7
- salabim-25.0.9.post2.dist-info/METADATA,sha256=1OIHo3tsAKXsDxdo8x3g6_-fXs9Hhlvh0hYoECG3XPs,3405
8
- salabim-25.0.9.post2.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
9
- salabim-25.0.9.post2.dist-info/top_level.txt,sha256=UE6zVlbi3F6T5ma1a_5TrojMaF21GYKDt9svvm0U4cQ,8
10
- salabim-25.0.9.post2.dist-info/RECORD,,
6
+ salabim/salabim.py,sha256=hL-5b2WhppIVwwldm-O5-pCFOEHRoFt1DhoIhCHf9-w,1121320
7
+ salabim-25.0.9.post4.dist-info/METADATA,sha256=t2mmahEmxd0puFxYki_G4vcb1k05dVyw9F-IQuNjs2A,3405
8
+ salabim-25.0.9.post4.dist-info/WHEEL,sha256=0CuiUZ_p9E4cD6NyLD6UG80LBXYyiSYZOKDm5lp32xk,91
9
+ salabim-25.0.9.post4.dist-info/top_level.txt,sha256=UE6zVlbi3F6T5ma1a_5TrojMaF21GYKDt9svvm0U4cQ,8
10
+ salabim-25.0.9.post4.dist-info/RECORD,,