salabim 24.0.12__py3-none-any.whl → 24.0.14.post3__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 +612 -60
- {salabim-24.0.12.dist-info → salabim-24.0.14.post3.dist-info}/METADATA +1 -1
- salabim-24.0.14.post3.dist-info/RECORD +10 -0
- {salabim-24.0.12.dist-info → salabim-24.0.14.post3.dist-info}/WHEEL +1 -1
- salabim-24.0.12.dist-info/RECORD +0 -10
- {salabim-24.0.12.dist-info → salabim-24.0.14.post3.dist-info}/top_level.txt +0 -0
salabim/salabim.py
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
# _ _ _ ____ _ _ ___ _
|
2
|
-
# ___ __ _ | | __ _ | |__ (_) _ __ ___ |___ \ | || | / _ \ / ||
|
3
|
-
# / __| / _` || | / _` || '_ \ | || '_ ` _ \ __) || || |_ | | | | |
|
4
|
-
# \__ \| (_| || || (_| || |_) || || | | | | | / __/ |__ _| _ | |_| | _ | |
|
5
|
-
# |___/ \__,_||_| \__,_||_.__/ |_||_| |_| |_| |_____| |_| (_) \___/ (_)|_
|
1
|
+
# _ _ _ ____ _ _ ___ _ _ _
|
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__ = "24.0.
|
10
|
+
__version__ = "24.0.14"
|
11
11
|
|
12
12
|
import heapq
|
13
13
|
import random
|
@@ -60,7 +60,7 @@ PyDroid = sys.platform == "linux" and any("pydroid" in v for v in os.environ.val
|
|
60
60
|
PyPy = platform.python_implementation() == "PyPy"
|
61
61
|
Chromebook = "penguin" in platform.uname()
|
62
62
|
PythonInExcel = not ("__file__" in globals())
|
63
|
-
AnacondaCode = sys.platform=="emscripten"
|
63
|
+
AnacondaCode = sys.platform == "emscripten"
|
64
64
|
|
65
65
|
|
66
66
|
def a_log(*args):
|
@@ -154,8 +154,9 @@ nan = float("nan")
|
|
154
154
|
if Pythonista or AnacondaCode or PythonInExcel:
|
155
155
|
_yieldless = False
|
156
156
|
else:
|
157
|
-
_yieldless=True
|
158
|
-
|
157
|
+
_yieldless = True
|
158
|
+
|
159
|
+
|
159
160
|
class QueueFullError(Exception):
|
160
161
|
pass
|
161
162
|
|
@@ -4144,7 +4145,7 @@ if Pythonista:
|
|
4144
4145
|
try:
|
4145
4146
|
ims = scene.load_pil_image(capture_image)
|
4146
4147
|
except SystemError:
|
4147
|
-
im_file = "temp.png" # hack for Pythonista 3.4
|
4148
|
+
im_file = "temp.png" # hack for Pythonista 3.4
|
4148
4149
|
capture_image.save(im_file, "PNG")
|
4149
4150
|
ims = scene.load_image_file(im_file)
|
4150
4151
|
scene.image(ims, 0, 0, *capture_image.size)
|
@@ -5717,7 +5718,7 @@ class Queue:
|
|
5717
5718
|
|
5718
5719
|
class Store(Queue):
|
5719
5720
|
def __init__(self, name: str = None, monitor: Any = True, fill: Iterable = None, capacity: float = inf, env: "Environment" = None, *args, **kwargs) -> None:
|
5720
|
-
super().__init__(name=name, monitor=monitor,fill=None,capacity=capacity, env=env, *args, **kwargs)
|
5721
|
+
super().__init__(name=name, monitor=monitor, fill=None, capacity=capacity, env=env, *args, **kwargs)
|
5721
5722
|
|
5722
5723
|
with self.env.suppress_trace():
|
5723
5724
|
self._to_store_requesters = Queue(f"{name}.to_store_requesters", env=env)
|
@@ -7981,6 +7982,10 @@ by adding:
|
|
7981
7982
|
----
|
7982
7983
|
Only if yieldless is False: if to be used for the current component, use ``yield self.cancel()``.
|
7983
7984
|
"""
|
7985
|
+
if self.status.value == data:
|
7986
|
+
if self.env._trace:
|
7987
|
+
self.env.print_trace("", "", "cancel (on data component) " + self.name() + " " + self._modetxt())
|
7988
|
+
return
|
7984
7989
|
if self.status.value != current:
|
7985
7990
|
self._checkisnotdata()
|
7986
7991
|
self._remove()
|
@@ -9048,10 +9053,7 @@ by adding:
|
|
9048
9053
|
self.status._value = waiting
|
9049
9054
|
self._reschedule(scheduled_time, schedule_priority, urgent, "wait", cap_now)
|
9050
9055
|
else:
|
9051
|
-
return
|
9052
|
-
if self.env._yieldless:
|
9053
|
-
if self is self.env._current_component:
|
9054
|
-
self.env._glet.switch()
|
9056
|
+
return
|
9055
9057
|
|
9056
9058
|
def _trywait(self):
|
9057
9059
|
if self.status.value == interrupted:
|
@@ -10000,6 +10002,211 @@ by adding:
|
|
10000
10002
|
return None
|
10001
10003
|
|
10002
10004
|
|
10005
|
+
class Event(Component):
|
10006
|
+
"""
|
10007
|
+
Event object
|
10008
|
+
|
10009
|
+
An event object is a specialized Component that is usually not subclassed.
|
10010
|
+
|
10011
|
+
Apart from the usual Component parameters it has an action parameter, to specifies what should
|
10012
|
+
happen after becoming active. This action is usually a lambda function.
|
10013
|
+
|
10014
|
+
Parameters
|
10015
|
+
----------
|
10016
|
+
action : callable
|
10017
|
+
function called when the component becomes current.
|
10018
|
+
|
10019
|
+
action_string : str
|
10020
|
+
string to be printed in trace when action gets executed (default: "action")
|
10021
|
+
|
10022
|
+
name : str
|
10023
|
+
name of the component.
|
10024
|
+
|
10025
|
+
if the name ends with a period (.),
|
10026
|
+
auto serializing will be applied
|
10027
|
+
|
10028
|
+
if the name end with a comma,
|
10029
|
+
auto serializing starting at 1 will be applied
|
10030
|
+
|
10031
|
+
if omitted, the name will be derived from the class
|
10032
|
+
it is defined in (lowercased)
|
10033
|
+
|
10034
|
+
at : float or distribution
|
10035
|
+
schedule time
|
10036
|
+
|
10037
|
+
if omitted, now is used
|
10038
|
+
|
10039
|
+
if distribution, the distribution is sampled
|
10040
|
+
|
10041
|
+
delay : float or distributiom
|
10042
|
+
schedule with a delay
|
10043
|
+
|
10044
|
+
if omitted, no delay
|
10045
|
+
|
10046
|
+
if distribution, the distribution is sampled
|
10047
|
+
|
10048
|
+
priority : float
|
10049
|
+
priority
|
10050
|
+
|
10051
|
+
default: 0
|
10052
|
+
|
10053
|
+
if a component has the same time on the event list, this component is sorted accoring to
|
10054
|
+
the priority.
|
10055
|
+
|
10056
|
+
urgent : bool
|
10057
|
+
urgency indicator
|
10058
|
+
|
10059
|
+
if False (default), the component will be scheduled
|
10060
|
+
behind all other components scheduled
|
10061
|
+
for the same time and priority
|
10062
|
+
|
10063
|
+
if True, the component will be scheduled
|
10064
|
+
in front of all components scheduled
|
10065
|
+
for the same time and priority
|
10066
|
+
|
10067
|
+
suppress_trace : bool
|
10068
|
+
suppress_trace indicator
|
10069
|
+
|
10070
|
+
if True, this component will be excluded from the trace
|
10071
|
+
|
10072
|
+
If False (default), the component will be traced
|
10073
|
+
|
10074
|
+
Can be queried or set later with the suppress_trace method.
|
10075
|
+
|
10076
|
+
suppress_pause_at_step : bool
|
10077
|
+
suppress_pause_at_step indicator
|
10078
|
+
|
10079
|
+
if True, if this component becomes current, do not pause when stepping
|
10080
|
+
|
10081
|
+
If False (default), the component will be paused when stepping
|
10082
|
+
|
10083
|
+
Can be queried or set later with the suppress_pause_at_step method.
|
10084
|
+
|
10085
|
+
skip_standby : bool
|
10086
|
+
skip_standby indicator
|
10087
|
+
|
10088
|
+
if True, after this component became current, do not activate standby components
|
10089
|
+
|
10090
|
+
If False (default), after the component became current activate standby components
|
10091
|
+
|
10092
|
+
Can be queried or set later with the skip_standby method.
|
10093
|
+
|
10094
|
+
mode : str preferred
|
10095
|
+
mode
|
10096
|
+
|
10097
|
+
will be used in trace and can be used in animations
|
10098
|
+
|
10099
|
+
if omitted, the mode will be "".
|
10100
|
+
|
10101
|
+
also mode_time will be set to now.
|
10102
|
+
|
10103
|
+
cap_now : bool
|
10104
|
+
indicator whether times (at, delay) in the past are allowed. If, so now() will be used.
|
10105
|
+
default: sys.default_cap_now(), usualy False
|
10106
|
+
|
10107
|
+
env : Environment
|
10108
|
+
environment where the component is defined
|
10109
|
+
|
10110
|
+
if omitted, default_env will be used
|
10111
|
+
"""
|
10112
|
+
|
10113
|
+
def __init__(
|
10114
|
+
self,
|
10115
|
+
action: Callable,
|
10116
|
+
action_string="action",
|
10117
|
+
name: str = None,
|
10118
|
+
at: Union[float, Callable] = None,
|
10119
|
+
delay: Union[float, Callable] = None,
|
10120
|
+
priority: float = None,
|
10121
|
+
urgent: bool = None,
|
10122
|
+
suppress_trace: bool = False,
|
10123
|
+
suppress_pause_at_step: bool = False,
|
10124
|
+
skip_standby: bool = False,
|
10125
|
+
mode: str = "",
|
10126
|
+
cap_now: bool = None,
|
10127
|
+
env: "Environment" = None,
|
10128
|
+
**kwargs,
|
10129
|
+
):
|
10130
|
+
self._action = action
|
10131
|
+
self._action_string = action_string
|
10132
|
+
self._action_taken = False
|
10133
|
+
if env is None:
|
10134
|
+
env = g.default_env
|
10135
|
+
super().__init__(
|
10136
|
+
name=name,
|
10137
|
+
at=at,
|
10138
|
+
delay=delay,
|
10139
|
+
priority=priority,
|
10140
|
+
urgent=urgent,
|
10141
|
+
suppress_trace=suppress_trace,
|
10142
|
+
suppress_pause_at_step=suppress_pause_at_step,
|
10143
|
+
skip_standby=skip_standby,
|
10144
|
+
mode=mode,
|
10145
|
+
cap_now=cap_now,
|
10146
|
+
env=env,
|
10147
|
+
process="process" if env._yieldless else "process_yield",
|
10148
|
+
**kwargs,
|
10149
|
+
)
|
10150
|
+
|
10151
|
+
def process_yield(self):
|
10152
|
+
self.env.print_trace("", "", self._action_string, "")
|
10153
|
+
self._action()
|
10154
|
+
self._action_taken = True
|
10155
|
+
return
|
10156
|
+
yield 1 # just to make it a generator
|
10157
|
+
|
10158
|
+
def process(self):
|
10159
|
+
self.env.print_trace("", "", self._action_string, "")
|
10160
|
+
self._action()
|
10161
|
+
self._action_taken = True
|
10162
|
+
|
10163
|
+
def action(self, value=None):
|
10164
|
+
"""
|
10165
|
+
action
|
10166
|
+
|
10167
|
+
Parameters
|
10168
|
+
----------
|
10169
|
+
value : callable
|
10170
|
+
new action callable
|
10171
|
+
|
10172
|
+
Returns
|
10173
|
+
-------
|
10174
|
+
current action : callable
|
10175
|
+
"""
|
10176
|
+
if value is not None:
|
10177
|
+
self._action = value
|
10178
|
+
return self._action
|
10179
|
+
|
10180
|
+
def action_string(self, value=None):
|
10181
|
+
"""
|
10182
|
+
action_string
|
10183
|
+
|
10184
|
+
Parameters
|
10185
|
+
----------
|
10186
|
+
value : string
|
10187
|
+
new action_string
|
10188
|
+
|
10189
|
+
Returns
|
10190
|
+
-------
|
10191
|
+
current action_string : string
|
10192
|
+
"""
|
10193
|
+
|
10194
|
+
if value is not None:
|
10195
|
+
self._action_string = value
|
10196
|
+
return self._action_string
|
10197
|
+
|
10198
|
+
def action_taken(self):
|
10199
|
+
"""
|
10200
|
+
action_taken
|
10201
|
+
|
10202
|
+
Returns
|
10203
|
+
-------
|
10204
|
+
action taken: bool
|
10205
|
+
True if action has been taken, False if not
|
10206
|
+
"""
|
10207
|
+
return self._action_taken
|
10208
|
+
|
10209
|
+
|
10003
10210
|
class Environment:
|
10004
10211
|
"""
|
10005
10212
|
environment object
|
@@ -10791,7 +10998,7 @@ class Environment:
|
|
10791
10998
|
if c.overridden_lineno:
|
10792
10999
|
self.print_trace(self.time_to_str(self._now - self._offset), c.name(), "current", s0=un_na(c.overridden_lineno))
|
10793
11000
|
else:
|
10794
|
-
self.print_trace(self.time_to_str(self._now - self._offset), c.name(), "current", s0=un_na(c.lineno_txt()))
|
11001
|
+
self.print_trace(self.time_to_str(self._now - self._offset), c.name(), "current", s0=un_na(c.lineno_txt()))
|
10795
11002
|
if c == self._main:
|
10796
11003
|
self.running = False
|
10797
11004
|
return
|
@@ -11141,13 +11348,13 @@ class Environment:
|
|
11141
11348
|
|
11142
11349
|
if width is not None:
|
11143
11350
|
if self._width != width:
|
11144
|
-
self._width = width
|
11351
|
+
self._width = int(width)
|
11145
11352
|
frame_changed = True
|
11146
11353
|
width_changed = True
|
11147
11354
|
|
11148
11355
|
if height is not None:
|
11149
11356
|
if self._height != height:
|
11150
|
-
self._height = height
|
11357
|
+
self._height = int(height)
|
11151
11358
|
frame_changed = True
|
11152
11359
|
height_changed = True
|
11153
11360
|
|
@@ -11506,7 +11713,7 @@ class Environment:
|
|
11506
11713
|
if self._video_pingpong:
|
11507
11714
|
self._images.extend(self._images[::-1])
|
11508
11715
|
if self._video_repeat == 1: # in case of repeat == 1, loop should not be specified (otherwise, it might show twice)
|
11509
|
-
if PythonInExcel or AnacondaCode:
|
11716
|
+
if PythonInExcel or AnacondaCode:
|
11510
11717
|
with b64_file_handler(self._video_name, mode="b", result=_pie_result) as f:
|
11511
11718
|
self._images[0].save(
|
11512
11719
|
f,
|
@@ -11527,7 +11734,7 @@ class Environment:
|
|
11527
11734
|
optimize=False,
|
11528
11735
|
)
|
11529
11736
|
else:
|
11530
|
-
if PythonInExcel or AnacondaCode:
|
11737
|
+
if PythonInExcel or AnacondaCode:
|
11531
11738
|
with b64_file_handler(self._video_name, mode="b", result=_pie_result) as f:
|
11532
11739
|
self._images[0].save(
|
11533
11740
|
f,
|
@@ -11596,7 +11803,8 @@ class Environment:
|
|
11596
11803
|
for ao in an_objects:
|
11597
11804
|
ao.make_pil_image(self.t())
|
11598
11805
|
if ao._image_visible and (include_topleft or not ao.getattr("in_topleft", False)):
|
11599
|
-
image.paste(ao._image, (int(ao._image_x), int(self._height - ao._image_y - ao._image.size[1])),
|
11806
|
+
image.paste(ao._image, (int(ao._image_x), int(self._height - ao._image_y - ao._image.size[1])),ao._image.convert("RGBA"),)
|
11807
|
+
|
11600
11808
|
|
11601
11809
|
return image.convert(mode)
|
11602
11810
|
|
@@ -12993,7 +13201,7 @@ class Environment:
|
|
12993
13201
|
if co is None:
|
12994
13202
|
if len(g.canvas_objects) >= self._maximum_number_of_bitmaps:
|
12995
13203
|
if overflow_image is None:
|
12996
|
-
overflow_image = Image.new("RGBA", (self._width, self._height), (0, 0, 0, 0))
|
13204
|
+
overflow_image = Image.new("RGBA", (int(self._width), int(self._height)), (0, 0, 0, 0))
|
12997
13205
|
overflow_image.paste(ao._image, (int(ao._image_x), int(self._height - ao._image_y - ao._image.size[1])), ao._image)
|
12998
13206
|
ao.canvas_object = None
|
12999
13207
|
else:
|
@@ -15218,10 +15426,20 @@ class Animate2dBase(DynamicClass):
|
|
15218
15426
|
spec = self.image(t)
|
15219
15427
|
image_container = ImageContainer(spec)
|
15220
15428
|
width = self.width(t)
|
15429
|
+
height = self.height(t)
|
15430
|
+
|
15221
15431
|
if width is None:
|
15222
|
-
|
15432
|
+
if height is None:
|
15433
|
+
width = image_container.images[0].size[0]
|
15434
|
+
height = image_container.images[0].size[1]
|
15435
|
+
else:
|
15436
|
+
width = height * image_container.images[0].size[0] / image_container.images[0].size[1]
|
15437
|
+
else:
|
15438
|
+
if height is None:
|
15439
|
+
height = width * image_container.images[0].size[1] / image_container.images[0].size[0]
|
15440
|
+
else:
|
15441
|
+
...
|
15223
15442
|
|
15224
|
-
height = width * image_container.images[0].size[1] / image_container.images[0].size[0]
|
15225
15443
|
if not self.screen_coordinates:
|
15226
15444
|
width *= self.env._scale
|
15227
15445
|
height *= self.env._scale
|
@@ -15240,7 +15458,6 @@ class Animate2dBase(DynamicClass):
|
|
15240
15458
|
offsety = offsety * self.env._scale
|
15241
15459
|
|
15242
15460
|
alpha = int(self.alpha(t))
|
15243
|
-
|
15244
15461
|
image, id = image_container.get_image(
|
15245
15462
|
(t - self.animation_start(t)) * self.animation_speed(t),
|
15246
15463
|
repeat=self.animation_repeat(t),
|
@@ -15248,6 +15465,7 @@ class Animate2dBase(DynamicClass):
|
|
15248
15465
|
t_from=self.animation_from(t),
|
15249
15466
|
t_to=self.animation_to(t),
|
15250
15467
|
)
|
15468
|
+
|
15251
15469
|
self._image_ident = (spec, id, width, height, angle, alpha, flip_horizontal, flip_vertical)
|
15252
15470
|
|
15253
15471
|
if self._image_ident != self._image_ident_prev:
|
@@ -15312,8 +15530,6 @@ class Animate2dBase(DynamicClass):
|
|
15312
15530
|
|
15313
15531
|
if not self.screen_coordinates:
|
15314
15532
|
fontsize = fontsize * self.env._scale
|
15315
|
-
# offsetx = offsetx * self.env._scale # ***
|
15316
|
-
# offsety = offsety * self.env._scale # ***
|
15317
15533
|
text_anchor = self.text_anchor(t)
|
15318
15534
|
|
15319
15535
|
if self.attached_to:
|
@@ -15347,6 +15563,7 @@ class Animate2dBase(DynamicClass):
|
|
15347
15563
|
qx = (x - self.env._x0) * self.env._scale
|
15348
15564
|
qy = (y - self.env._y0) * self.env._scale
|
15349
15565
|
max_lines = self.max_lines(t)
|
15566
|
+
|
15350
15567
|
self._image_ident = (text, fontname, fontsize, angle, textcolor, max_lines)
|
15351
15568
|
if self._image_ident != self._image_ident_prev:
|
15352
15569
|
font, heightA = getfont(fontname, fontsize)
|
@@ -15529,6 +15746,9 @@ class AnimateClassic(Animate2dBase):
|
|
15529
15746
|
def width(self, t):
|
15530
15747
|
return self.master.width(t)
|
15531
15748
|
|
15749
|
+
def height(self, t):
|
15750
|
+
return self.master.height(t)
|
15751
|
+
|
15532
15752
|
def anchor(self, t):
|
15533
15753
|
return self.master.anchor(t)
|
15534
15754
|
|
@@ -15756,6 +15976,11 @@ class Animate:
|
|
15756
15976
|
|
15757
15977
|
if omitted or None, no scaling
|
15758
15978
|
|
15979
|
+
height0 : float
|
15980
|
+
width of the image to be displayed at time t0
|
15981
|
+
|
15982
|
+
if omitted or None, no scaling
|
15983
|
+
|
15759
15984
|
t1 : float
|
15760
15985
|
time of end of the animation (default inf)
|
15761
15986
|
|
@@ -15824,6 +16049,9 @@ class Animate:
|
|
15824
16049
|
width1 : float
|
15825
16050
|
width of the image to be displayed at time t1 (default: width0)
|
15826
16051
|
|
16052
|
+
height1 : float
|
16053
|
+
width of the image to be displayed at time t1 (default: height0)
|
16054
|
+
|
15827
16055
|
over3d : bool
|
15828
16056
|
if True, this object will be rendered to the OpenGL window
|
15829
16057
|
|
@@ -15892,6 +16120,7 @@ class Animate:
|
|
15892
16120
|
font -
|
15893
16121
|
fontsize0,fontsize1 -
|
15894
16122
|
width0,width1 -
|
16123
|
+
height0,height1 -
|
15895
16124
|
====================== ========= ========= ========= ========= ========= =========
|
15896
16125
|
"""
|
15897
16126
|
|
@@ -15927,6 +16156,7 @@ class Animate:
|
|
15927
16156
|
alpha0: float = 255,
|
15928
16157
|
fontsize0: float = 20,
|
15929
16158
|
width0: float = None,
|
16159
|
+
height0: float = None,
|
15930
16160
|
t1: float = None,
|
15931
16161
|
x1: float = None,
|
15932
16162
|
y1: float = None,
|
@@ -15945,6 +16175,7 @@ class Animate:
|
|
15945
16175
|
alpha1: float = None,
|
15946
16176
|
fontsize1: float = None,
|
15947
16177
|
width1: float = None,
|
16178
|
+
height1: float = None,
|
15948
16179
|
xy_anchor: str = "",
|
15949
16180
|
over3d: bool = None,
|
15950
16181
|
flip_horizontal: bool = False,
|
@@ -15991,10 +16222,12 @@ class Animate:
|
|
15991
16222
|
self.text0 = text
|
15992
16223
|
|
15993
16224
|
if image is None:
|
15994
|
-
self.width0 = 0 # just to be able to
|
16225
|
+
self.width0 = 0 # just to be able to interpolat
|
16226
|
+
self.height0 = 0
|
15995
16227
|
else:
|
15996
16228
|
self.image0 = image
|
15997
16229
|
self.width0 = width0 # None means original size
|
16230
|
+
self.height0 = height0
|
15998
16231
|
|
15999
16232
|
self.as_points0 = as_points
|
16000
16233
|
self.font0 = font
|
@@ -16056,7 +16289,7 @@ class Animate:
|
|
16056
16289
|
self.alpha1 = self.alpha0 if alpha1 is None else alpha1
|
16057
16290
|
self.fontsize1 = self.fontsize0 if fontsize1 is None else fontsize1
|
16058
16291
|
self.width1 = self.width0 if width1 is None else width1
|
16059
|
-
|
16292
|
+
self.height1 = self.height0 if height1 is None else height1
|
16060
16293
|
self.t1 = inf if t1 is None else t1
|
16061
16294
|
if self.env._animate_debug:
|
16062
16295
|
self.caller = self.env._frame_to_lineno(_get_caller_frame(), add_filename=True)
|
@@ -16115,6 +16348,7 @@ class Animate:
|
|
16115
16348
|
alpha0=None,
|
16116
16349
|
fontsize0=None,
|
16117
16350
|
width0=None,
|
16351
|
+
height0=None,
|
16118
16352
|
xy_anchor1=None,
|
16119
16353
|
as_points=None,
|
16120
16354
|
t1=None,
|
@@ -16135,6 +16369,7 @@ class Animate:
|
|
16135
16369
|
alpha1=None,
|
16136
16370
|
fontsize1=None,
|
16137
16371
|
width1=None,
|
16372
|
+
height1=None,
|
16138
16373
|
flip_horizontal=None,
|
16139
16374
|
flip_vertical=None,
|
16140
16375
|
animation_start=None,
|
@@ -16287,6 +16522,11 @@ class Animate:
|
|
16287
16522
|
|
16288
16523
|
if None, the original width of the image will be used
|
16289
16524
|
|
16525
|
+
height0 : float
|
16526
|
+
height of the image to be displayed at time t0 (default see below)
|
16527
|
+
|
16528
|
+
if None, the original height of the image will be used
|
16529
|
+
|
16290
16530
|
t1 : float
|
16291
16531
|
time of end of the animation (default: inf)
|
16292
16532
|
|
@@ -16353,6 +16593,8 @@ class Animate:
|
|
16353
16593
|
width1 : float
|
16354
16594
|
width of the image to be displayed at time t1 (default: width0)
|
16355
16595
|
|
16596
|
+
height1 : float
|
16597
|
+
height of the image to be displayed at time t1 (default: height0)
|
16356
16598
|
|
16357
16599
|
Note
|
16358
16600
|
----
|
@@ -16388,6 +16630,8 @@ class Animate:
|
|
16388
16630
|
self.max_lines0 = max_lines
|
16389
16631
|
|
16390
16632
|
self.width0 = self.width() if width0 is None else width0
|
16633
|
+
self.height0 = self.height() if height0 is None else height0
|
16634
|
+
|
16391
16635
|
if image is not None:
|
16392
16636
|
self.image0 = image
|
16393
16637
|
|
@@ -16434,6 +16678,7 @@ class Animate:
|
|
16434
16678
|
self.alpha1 = self.alpha0 if alpha1 is None else alpha1
|
16435
16679
|
self.fontsize1 = self.fontsize0 if fontsize1 is None else fontsize1
|
16436
16680
|
self.width1 = self.width0 if width1 is None else width1
|
16681
|
+
self.height1 = self.height0 if height1 is None else height1
|
16437
16682
|
self.xy_anchor1 = self.xy_anchor0 if xy_anchor1 is None else xy_anchor1
|
16438
16683
|
|
16439
16684
|
self.t1 = inf if t1 is None else t1
|
@@ -16731,7 +16976,7 @@ class Animate:
|
|
16731
16976
|
|
16732
16977
|
def width(self, t=None):
|
16733
16978
|
"""
|
16734
|
-
width
|
16979
|
+
width of an animated image object. May be overridden.
|
16735
16980
|
|
16736
16981
|
Parameters
|
16737
16982
|
----------
|
@@ -16756,6 +17001,33 @@ class Animate:
|
|
16756
17001
|
|
16757
17002
|
return interpolate((self.env._now if t is None else t), self.t0, self.t1, width0, width1)
|
16758
17003
|
|
17004
|
+
def height(self, t=None):
|
17005
|
+
"""
|
17006
|
+
height of an animated image object. May be overridden.
|
17007
|
+
|
17008
|
+
Parameters
|
17009
|
+
----------
|
17010
|
+
t : float
|
17011
|
+
current time
|
17012
|
+
|
17013
|
+
Returns
|
17014
|
+
-------
|
17015
|
+
height : float
|
17016
|
+
default behaviour: linear interpolation between self.height0 and self.height1
|
17017
|
+
|
17018
|
+
if None, the original height of the image will be used
|
17019
|
+
"""
|
17020
|
+
height0 = self.height0
|
17021
|
+
height1 = self.height1
|
17022
|
+
if height0 is None and height1 is None:
|
17023
|
+
return None
|
17024
|
+
if height0 is None:
|
17025
|
+
height0 = ImageContainer(self.image0).images[0].size[0]
|
17026
|
+
if height1 is None:
|
17027
|
+
height1 = ImageContainer(self.image1).images[0].size[0]
|
17028
|
+
|
17029
|
+
return interpolate((self.env._now if t is None else t), self.t0, self.t1, height0, height1)
|
17030
|
+
|
16759
17031
|
def fontsize(self, t=None):
|
16760
17032
|
"""
|
16761
17033
|
fontsize of an animate object. May be overridden.
|
@@ -19449,6 +19721,8 @@ class AnimateImage(Animate2dBase):
|
|
19449
19721
|
width : float
|
19450
19722
|
width of the image (default: None = no scaling)
|
19451
19723
|
|
19724
|
+
heighth : float
|
19725
|
+
height of the image (default: None = no scaling)
|
19452
19726
|
|
19453
19727
|
text : str, tuple or list
|
19454
19728
|
the text to be displayed
|
@@ -19584,6 +19858,7 @@ class AnimateImage(Animate2dBase):
|
|
19584
19858
|
x: Union[float, Callable] = None,
|
19585
19859
|
y: Union[float, Callable] = None,
|
19586
19860
|
width: Union[float, Callable] = None,
|
19861
|
+
height: Union[float, Callable] = None,
|
19587
19862
|
text: Union[str, Callable] = None,
|
19588
19863
|
fontsize: Union[float, Callable] = None,
|
19589
19864
|
textcolor: Union[ColorType, Callable] = None,
|
@@ -19626,6 +19901,7 @@ class AnimateImage(Animate2dBase):
|
|
19626
19901
|
x=0,
|
19627
19902
|
y=0,
|
19628
19903
|
width=None,
|
19904
|
+
height=None,
|
19629
19905
|
text="",
|
19630
19906
|
fontsize=15,
|
19631
19907
|
textcolor="bg",
|
@@ -19708,10 +19984,10 @@ class ComponentGenerator(Component):
|
|
19708
19984
|
|
19709
19985
|
Parameters
|
19710
19986
|
----------
|
19711
|
-
component_class : callable, usually a subclass of Component or Pdf or Cdf distribution
|
19987
|
+
component_class : callable, usually a subclass of Component or Pdf/Pmf or Cdf distribution
|
19712
19988
|
the type of components to be generated
|
19713
19989
|
|
19714
|
-
in case of a distribution, the Pdf or Cdf should return a callable
|
19990
|
+
in case of a distribution, the Pdf/Pmf or Cdf should return a callable
|
19715
19991
|
|
19716
19992
|
generator_name : str
|
19717
19993
|
name of the component generator.
|
@@ -19822,6 +20098,13 @@ class ComponentGenerator(Component):
|
|
19822
20098
|
|
19823
20099
|
e.g. env.main().activate()
|
19824
20100
|
|
20101
|
+
moments : iterable
|
20102
|
+
specifies the moments when the components have to be generated. It is not required that these are sorted.
|
20103
|
+
|
20104
|
+
note that the moments are specified in the current time unit
|
20105
|
+
|
20106
|
+
cannot be used together with at, delay, till, duration, number, iat,force_at, force_till, disturbance or equidistant
|
20107
|
+
|
19825
20108
|
env : Environment
|
19826
20109
|
environment where the component is defined
|
19827
20110
|
|
@@ -19850,6 +20133,7 @@ class ComponentGenerator(Component):
|
|
19850
20133
|
disturbance: Callable = None,
|
19851
20134
|
equidistant: bool = False,
|
19852
20135
|
at_end: Callable = None,
|
20136
|
+
moments: Iterable = None,
|
19853
20137
|
env: "Environment" = None,
|
19854
20138
|
**kwargs,
|
19855
20139
|
):
|
@@ -19867,6 +20151,15 @@ class ComponentGenerator(Component):
|
|
19867
20151
|
|
19868
20152
|
if not callable(component_class):
|
19869
20153
|
raise ValueError("component_class must be a callable")
|
20154
|
+
if moments is not None:
|
20155
|
+
if any(prop for prop in (at, delay, till, duration, number, iat, force_at, force_till, disturbance, equidistant)):
|
20156
|
+
raise ValueError(
|
20157
|
+
"specifying at, delay, till,duration, number, iat,force_at, force_till, disturbance or equidistant is not allowed, if moments is specified"
|
20158
|
+
)
|
20159
|
+
if callable(moments):
|
20160
|
+
moments = moments()
|
20161
|
+
moments = sorted([env.spec_to_time(moment) for moment in moments])
|
20162
|
+
|
19870
20163
|
self.component_class = component_class
|
19871
20164
|
self.iat = iat
|
19872
20165
|
self.disturbance = disturbance
|
@@ -19909,25 +20202,26 @@ class ComponentGenerator(Component):
|
|
19909
20202
|
at = None
|
19910
20203
|
process = ""
|
19911
20204
|
else:
|
19912
|
-
if self.iat is None and not equidistant:
|
19913
|
-
if
|
19914
|
-
|
19915
|
-
|
19916
|
-
|
19917
|
-
|
19918
|
-
|
19919
|
-
|
19920
|
-
if
|
19921
|
-
if
|
19922
|
-
|
19923
|
-
|
19924
|
-
|
19925
|
-
|
19926
|
-
|
19927
|
-
|
19928
|
-
|
19929
|
-
|
19930
|
-
|
20205
|
+
if (self.iat is None and not equidistant) or moments:
|
20206
|
+
if not moments:
|
20207
|
+
if till == inf or self.number == inf:
|
20208
|
+
raise ValueError("iat not specified --> till and number need to be specified")
|
20209
|
+
if disturbance is not None:
|
20210
|
+
raise ValueError("iat not specified --> disturbance not allowed")
|
20211
|
+
|
20212
|
+
moments = sorted([Uniform(at, till)() for _ in range(self.number)])
|
20213
|
+
if force_at or force_till:
|
20214
|
+
if number == 1:
|
20215
|
+
if force_at and force_till:
|
20216
|
+
raise ValueError("force_at and force_till does not allow number=1")
|
20217
|
+
moments = [at] if force_at else [till]
|
20218
|
+
else:
|
20219
|
+
v_at = at if force_at else moments[0]
|
20220
|
+
v_till = till if force_till else moments[-1]
|
20221
|
+
min_moment = moments[0]
|
20222
|
+
max_moment = moments[-1]
|
20223
|
+
moments = [interpolate(moment, min_moment, max_moment, v_at, v_till) for moment in moments]
|
20224
|
+
self.intervals = [t1 - t0 for t0, t1 in zip([0] + moments, moments)]
|
19931
20225
|
at = self.intervals[0]
|
19932
20226
|
self.intervals[0] = 0
|
19933
20227
|
process = "do_spread_yieldless" if env._yieldless else "do_spread"
|
@@ -20253,7 +20547,7 @@ class _Distribution:
|
|
20253
20547
|
If, after number_of_tries retries, the sampled value is still not within the given bounds,
|
20254
20548
|
fail_value will be returned
|
20255
20549
|
|
20256
|
-
Samples that cannot be converted (only possible with
|
20550
|
+
Samples that cannot be converted (only possible with /Pmf and CumPdf/CumPmf) to float
|
20257
20551
|
are assumed to be within the bounds.
|
20258
20552
|
"""
|
20259
20553
|
return Bounded(self, lowerbound, upperbound, fail_value, number_of_retries, include_lowerbound, include_upperbound).sample()
|
@@ -20493,7 +20787,7 @@ class Bounded(_Distribution):
|
|
20493
20787
|
If, after number_of_tries retries, the sampled value is still not within the given bounds,
|
20494
20788
|
fail_value will be returned
|
20495
20789
|
|
20496
|
-
Samples that cannot be converted to float (only possible with Pdf and CumPdf)
|
20790
|
+
Samples that cannot be converted to float (only possible with Pdf/Pmf and CumPdf)
|
20497
20791
|
are assumed to be within the bounds.
|
20498
20792
|
"""
|
20499
20793
|
|
@@ -21989,6 +22283,9 @@ class Pdf(_Distribution):
|
|
21989
22283
|
|
21990
22284
|
If it is a salabim distribution, not the distribution,
|
21991
22285
|
but a sample will be returned when calling sample.
|
22286
|
+
|
22287
|
+
|
22288
|
+
This method is also available under the name Pmf
|
21992
22289
|
"""
|
21993
22290
|
|
21994
22291
|
def __init__(self, spec: Union[Iterable, Dict], probabilities=None, time_unit: str = None, randomstream: Any = None, env: "Environment" = None):
|
@@ -22133,9 +22430,151 @@ class Pdf(_Distribution):
|
|
22133
22430
|
return self._mean
|
22134
22431
|
|
22135
22432
|
|
22433
|
+
class Pmf(Pdf):
|
22434
|
+
"""
|
22435
|
+
Probability mass function
|
22436
|
+
|
22437
|
+
Parameters
|
22438
|
+
----------
|
22439
|
+
spec : list, tuple or dict
|
22440
|
+
either
|
22441
|
+
|
22442
|
+
- if no probabilities specified:
|
22443
|
+
|
22444
|
+
list/tuple with x-values and corresponding probability
|
22445
|
+
dict where the keys are re x-values and the values are probabilities
|
22446
|
+
(x0, p0, x1, p1, ...xn,pn)
|
22447
|
+
|
22448
|
+
- if probabilities is specified:
|
22449
|
+
|
22450
|
+
list with x-values
|
22451
|
+
|
22452
|
+
probabilities : iterable or float
|
22453
|
+
if omitted, spec contains the probabilities
|
22454
|
+
|
22455
|
+
the iterable (p0, p1, ...pn) contains the probabilities of the corresponding
|
22456
|
+
x-values from spec.
|
22457
|
+
|
22458
|
+
alternatively, if a float is given (e.g. 1), all x-values
|
22459
|
+
have equal probability. The value is not important.
|
22460
|
+
|
22461
|
+
time_unit : str
|
22462
|
+
specifies the time unit
|
22463
|
+
|
22464
|
+
must be one of "years", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds"
|
22465
|
+
|
22466
|
+
default : no conversion
|
22467
|
+
|
22468
|
+
|
22469
|
+
randomstream : randomstream
|
22470
|
+
if omitted, random will be used
|
22471
|
+
|
22472
|
+
if used as random.Random(12299)
|
22473
|
+
it assigns a new stream with the specified seed
|
22474
|
+
|
22475
|
+
env : Environment
|
22476
|
+
environment where the distribution is defined
|
22477
|
+
|
22478
|
+
if omitted, default_env will be used
|
22479
|
+
|
22480
|
+
Note
|
22481
|
+
----
|
22482
|
+
p0+p1=...+pn>0
|
22483
|
+
|
22484
|
+
all densities are auto scaled according to the sum of p0 to pn,
|
22485
|
+
so no need to have p0 to pn add up to 1 or 100.
|
22486
|
+
|
22487
|
+
The x-values can be any type.
|
22488
|
+
|
22489
|
+
If it is a salabim distribution, not the distribution,
|
22490
|
+
but a sample will be returned when calling sample.
|
22491
|
+
|
22492
|
+
This method is also available under the name Pdf
|
22493
|
+
|
22494
|
+
"""
|
22495
|
+
|
22496
|
+
def __repr__(self):
|
22497
|
+
return "Pmf"
|
22498
|
+
|
22499
|
+
def print_info(self, as_str: bool = False, file: TextIO = None) -> str:
|
22500
|
+
"""
|
22501
|
+
prints information about the distribution
|
22502
|
+
|
22503
|
+
Parameters
|
22504
|
+
----------
|
22505
|
+
as_str: bool
|
22506
|
+
if False (default), print the info
|
22507
|
+
if True, return a string containing the info
|
22508
|
+
|
22509
|
+
file: file
|
22510
|
+
if None(default), all output is directed to stdout
|
22511
|
+
|
22512
|
+
otherwise, the output is directed to the file
|
22513
|
+
|
22514
|
+
Returns
|
22515
|
+
-------
|
22516
|
+
info (if as_str is True) : str
|
22517
|
+
"""
|
22518
|
+
result = []
|
22519
|
+
result.append("Pmf distribution " + hex(id(self)))
|
22520
|
+
result.append(" randomstream=" + hex(id(self.randomstream)))
|
22521
|
+
return return_or_print(result, as_str, file)
|
22522
|
+
|
22523
|
+
def sample(self, n: int = None) -> Any:
|
22524
|
+
"""
|
22525
|
+
Parameters
|
22526
|
+
----------
|
22527
|
+
n : number of samples : int
|
22528
|
+
if not specified, specifies just return one sample, as usual
|
22529
|
+
|
22530
|
+
if specified, return a list of n sampled values from the distribution without replacement.
|
22531
|
+
This requires that all probabilities are equal.
|
22532
|
+
|
22533
|
+
If n > number of values in the Pmf distribution, n is assumed to be the number of values
|
22534
|
+
in the distribution.
|
22535
|
+
|
22536
|
+
If a sampled value is a distribution, a sample from that distribution will be returned.
|
22537
|
+
|
22538
|
+
Returns
|
22539
|
+
-------
|
22540
|
+
Sample of the distribution : any (usually float) or list
|
22541
|
+
In case n is specified, returns a list of n values
|
22542
|
+
|
22543
|
+
"""
|
22544
|
+
if self.supports_n:
|
22545
|
+
if n is None:
|
22546
|
+
return self.randomstream.sample(self._x, 1)[0]
|
22547
|
+
else:
|
22548
|
+
if n < 0:
|
22549
|
+
raise ValueError("n < 0")
|
22550
|
+
n = min(n, len(self._x))
|
22551
|
+
xs = self.randomstream.sample(self._x, n)
|
22552
|
+
return [x.sample() if isinstance(x, _Distribution) else x for x in xs]
|
22553
|
+
else:
|
22554
|
+
if n is None:
|
22555
|
+
r = self.randomstream.random()
|
22556
|
+
for cum, x in zip([0] + self._cum, [0] + self._x):
|
22557
|
+
if r <= cum:
|
22558
|
+
if isinstance(x, _Distribution):
|
22559
|
+
return x.sample()
|
22560
|
+
return x
|
22561
|
+
else:
|
22562
|
+
raise ValueError("not all probabilities are the same")
|
22563
|
+
|
22564
|
+
def mean(self) -> float:
|
22565
|
+
"""
|
22566
|
+
Returns
|
22567
|
+
-------
|
22568
|
+
mean of the distribution : float
|
22569
|
+
if the mean can't be calculated (if not all x-values are scalars or distributions),
|
22570
|
+
nan will be returned.
|
22571
|
+
"""
|
22572
|
+
return self._mean
|
22573
|
+
|
22574
|
+
|
22136
22575
|
class CumPdf(_Distribution):
|
22137
22576
|
"""
|
22138
|
-
Cumulative Probability
|
22577
|
+
Cumulative Probability mass function
|
22139
22578
|
|
22140
22579
|
Parameters
|
22141
22580
|
----------
|
@@ -22188,6 +22627,8 @@ class CumPdf(_Distribution):
|
|
22188
22627
|
|
22189
22628
|
If it is a salabim distribution, not the distribution,
|
22190
22629
|
but a sample will be returned when calling sample.
|
22630
|
+
|
22631
|
+
This method is also available under the name CumPmf
|
22191
22632
|
"""
|
22192
22633
|
|
22193
22634
|
def __init__(
|
@@ -22303,6 +22744,116 @@ class CumPdf(_Distribution):
|
|
22303
22744
|
return self._mean
|
22304
22745
|
|
22305
22746
|
|
22747
|
+
class CumPmf(CumPdf):
|
22748
|
+
"""
|
22749
|
+
Cumulative Probability mass function
|
22750
|
+
|
22751
|
+
Parameters
|
22752
|
+
----------
|
22753
|
+
spec : list or tuple
|
22754
|
+
either
|
22755
|
+
|
22756
|
+
- if no cumprobabilities specified:
|
22757
|
+
|
22758
|
+
list with x-values and corresponding cumulative probability
|
22759
|
+
(x0, p0, x1, p1, ...xn,pn)
|
22760
|
+
|
22761
|
+
- if cumprobabilities is specified:
|
22762
|
+
|
22763
|
+
list with x-values
|
22764
|
+
|
22765
|
+
cumprobabilities : list, tuple or float
|
22766
|
+
if omitted, spec contains the probabilities
|
22767
|
+
|
22768
|
+
the list (p0, p1, ...pn) contains the cumulative probabilities of the corresponding
|
22769
|
+
x-values from spec.
|
22770
|
+
|
22771
|
+
|
22772
|
+
time_unit : str
|
22773
|
+
specifies the time unit
|
22774
|
+
|
22775
|
+
must be one of "years", "weeks", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds"
|
22776
|
+
|
22777
|
+
default : no conversion
|
22778
|
+
|
22779
|
+
|
22780
|
+
randomstream : randomstream
|
22781
|
+
if omitted, random will be used
|
22782
|
+
|
22783
|
+
if used as random.Random(12299)
|
22784
|
+
it assigns a new stream with the specified seed
|
22785
|
+
|
22786
|
+
env : Environment
|
22787
|
+
environment where the distribution is defined
|
22788
|
+
|
22789
|
+
if omitted, default_env will be used
|
22790
|
+
|
22791
|
+
Note
|
22792
|
+
----
|
22793
|
+
p0<=p1<=..pn>0
|
22794
|
+
|
22795
|
+
all densities are auto scaled according to pn,
|
22796
|
+
so no need to have pn be 1 or 100.
|
22797
|
+
|
22798
|
+
The x-values can be any type.
|
22799
|
+
|
22800
|
+
If it is a salabim distribution, not the distribution,
|
22801
|
+
but a sample will be returned when calling sample.
|
22802
|
+
|
22803
|
+
This method is also available under the name CumPdf
|
22804
|
+
"""
|
22805
|
+
|
22806
|
+
def __repr__(self):
|
22807
|
+
return "CumPmf"
|
22808
|
+
|
22809
|
+
def print_info(self, as_str: bool = False, file: TextIO = None) -> str:
|
22810
|
+
"""
|
22811
|
+
prints information about the distribution
|
22812
|
+
|
22813
|
+
Parameters
|
22814
|
+
----------
|
22815
|
+
as_str: bool
|
22816
|
+
if False (default), print the info
|
22817
|
+
if True, return a string containing the info
|
22818
|
+
|
22819
|
+
file: file
|
22820
|
+
if None(default), all output is directed to stdout
|
22821
|
+
|
22822
|
+
otherwise, the output is directed to the file
|
22823
|
+
|
22824
|
+
Returns
|
22825
|
+
-------
|
22826
|
+
info (if as_str is True) : str
|
22827
|
+
"""
|
22828
|
+
result = []
|
22829
|
+
result.append("CumPmf distribution " + hex(id(self)))
|
22830
|
+
result.append(" randomstream=" + hex(id(self.randomstream)))
|
22831
|
+
return return_or_print(result, as_str, file)
|
22832
|
+
|
22833
|
+
def sample(self) -> Any:
|
22834
|
+
"""
|
22835
|
+
Returns
|
22836
|
+
-------
|
22837
|
+
Sample of the distribution : any (usually float)
|
22838
|
+
"""
|
22839
|
+
r = self.randomstream.random()
|
22840
|
+
for cum, x in zip([0] + self._cum, [0] + self._x):
|
22841
|
+
if r <= cum:
|
22842
|
+
if isinstance(x, _Distribution):
|
22843
|
+
return x.sample()
|
22844
|
+
return x
|
22845
|
+
|
22846
|
+
def mean(self) -> float:
|
22847
|
+
"""
|
22848
|
+
Returns
|
22849
|
+
-------
|
22850
|
+
mean of the distribution : float
|
22851
|
+
if the mean can't be calculated (if not all x-values are scalars or distributions),
|
22852
|
+
nan will be returned.
|
22853
|
+
"""
|
22854
|
+
return self._mean
|
22855
|
+
|
22856
|
+
|
22306
22857
|
class External(_Distribution):
|
22307
22858
|
"""
|
22308
22859
|
External distribution function
|
@@ -23902,7 +24453,7 @@ class _APNG:
|
|
23902
24453
|
|
23903
24454
|
def to_bytes(self):
|
23904
24455
|
CHUNK_BEFORE_IDAT = {"cHRM", "gAMA", "iCCP", "sBIT", "sRGB", "bKGD", "hIST", "tRNS", "pHYs", "sPLT", "tIME", "PLTE"}
|
23905
|
-
PNG_SIGN = b"\x89\x50\
|
24456
|
+
PNG_SIGN = b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
|
23906
24457
|
out = [PNG_SIGN]
|
23907
24458
|
other_chunks = []
|
23908
24459
|
seq = 0
|
@@ -26316,7 +26867,7 @@ def fonts():
|
|
26316
26867
|
|
26317
26868
|
for dir, recursive in dir_recursives:
|
26318
26869
|
for file_path in dir.glob("**/*.*" if recursive else "*.*"):
|
26319
|
-
if file_path.suffix.lower() == ".ttf":
|
26870
|
+
if file_path.suffix.lower() == ".ttf":
|
26320
26871
|
file = str(file_path)
|
26321
26872
|
fn = os.path.basename(file).split(".")[0]
|
26322
26873
|
if "_std_fonts" in globals() and fn in _std_fonts(): # test for availabiitly, because of minimized version
|
@@ -26376,7 +26927,8 @@ def getfont(fontname, fontsize):
|
|
26376
26927
|
return getfont.lookup[(fontname, fontsize)]
|
26377
26928
|
else:
|
26378
26929
|
getfont.lookup = {}
|
26379
|
-
|
26930
|
+
if fontname == "":
|
26931
|
+
a = 1
|
26380
26932
|
if isinstance(fontname, str):
|
26381
26933
|
fontlist1 = [fontname]
|
26382
26934
|
else:
|
@@ -26409,7 +26961,8 @@ def getfont(fontname, fontsize):
|
|
26409
26961
|
result = ImageFont.truetype(filename, size=int(fontsize))
|
26410
26962
|
else:
|
26411
26963
|
# refer to https://github.com/python-pillow/Pillow/issues/3730 for explanation (in order to load >= 500 fonts)
|
26412
|
-
|
26964
|
+
with open(filename, "rb") as f:
|
26965
|
+
result = ImageFont.truetype(font=io.BytesIO(f.read()), size=int(fontsize))
|
26413
26966
|
break
|
26414
26967
|
except Exception:
|
26415
26968
|
raise
|
@@ -26948,7 +27501,7 @@ def reset() -> None:
|
|
26948
27501
|
g.tkinter_loaded = "?"
|
26949
27502
|
g.image_container_cache = {}
|
26950
27503
|
g._default_cap_now = False
|
26951
|
-
g._captured_stdout=[]
|
27504
|
+
g._captured_stdout = []
|
26952
27505
|
|
26953
27506
|
random_seed() # always start with seed 1234567
|
26954
27507
|
|
@@ -27181,7 +27734,6 @@ reset()
|
|
27181
27734
|
set_environment_aliases()
|
27182
27735
|
|
27183
27736
|
if __name__ == "__main__":
|
27184
|
-
|
27185
27737
|
sys.path.insert(0, str(Path(__file__).parent / ".." / "misc"))
|
27186
27738
|
try:
|
27187
27739
|
import salabim_exp
|
@@ -0,0 +1,10 @@
|
|
1
|
+
salabim/DejaVuSansMono.ttf,sha256=Z_oIXp5yp1Zaw2y2p3vaxwHhjHpG0MFbmwhxSh4aIEI,335068
|
2
|
+
salabim/LICENSE.txt,sha256=qHlBa-POyexatCxDTjSKMlYtkBFQDn9lu-YV_1L6V0U,1106
|
3
|
+
salabim/__init__.py,sha256=r7qPLvlmX0dkZDyjuTo8Jo3ex3sD1L4pmK6K5ib9vyw,56
|
4
|
+
salabim/calibri.ttf,sha256=RWpf8Uo31RfvGGNaSt9-2sXSuN87AVE_NFMRsV3LhBk,1330156
|
5
|
+
salabim/mplus-1m-regular.ttf,sha256=EuFHr90BJjuAn_r5MleJFN-WfkeWJ4tf7DweI5zr8tU,289812
|
6
|
+
salabim/salabim.py,sha256=LkXx4KGzg9FaYfe4NUBb2Zm2Iy4v1B2kyHks7cwsWoI,1113664
|
7
|
+
salabim-24.0.14.post3.dist-info/METADATA,sha256=4yHEwkcBMUAj2CtFsi3y4s7zkJTzSvLkkm0h3g6vgiI,3456
|
8
|
+
salabim-24.0.14.post3.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
9
|
+
salabim-24.0.14.post3.dist-info/top_level.txt,sha256=UE6zVlbi3F6T5ma1a_5TrojMaF21GYKDt9svvm0U4cQ,8
|
10
|
+
salabim-24.0.14.post3.dist-info/RECORD,,
|
salabim-24.0.12.dist-info/RECORD
DELETED
@@ -1,10 +0,0 @@
|
|
1
|
-
salabim/DejaVuSansMono.ttf,sha256=Z_oIXp5yp1Zaw2y2p3vaxwHhjHpG0MFbmwhxSh4aIEI,335068
|
2
|
-
salabim/LICENSE.txt,sha256=qHlBa-POyexatCxDTjSKMlYtkBFQDn9lu-YV_1L6V0U,1106
|
3
|
-
salabim/__init__.py,sha256=r7qPLvlmX0dkZDyjuTo8Jo3ex3sD1L4pmK6K5ib9vyw,56
|
4
|
-
salabim/calibri.ttf,sha256=RWpf8Uo31RfvGGNaSt9-2sXSuN87AVE_NFMRsV3LhBk,1330156
|
5
|
-
salabim/mplus-1m-regular.ttf,sha256=EuFHr90BJjuAn_r5MleJFN-WfkeWJ4tf7DweI5zr8tU,289812
|
6
|
-
salabim/salabim.py,sha256=i5fPqlJSk3PRWFFZ7Z6RVsIWRI0EwQIeaN99fu5mCV0,1097596
|
7
|
-
salabim-24.0.12.dist-info/METADATA,sha256=PlkVJ2Qk6CFySH31iSJDmGZQ2Yrzolam1TIIuwqQN3A,3450
|
8
|
-
salabim-24.0.12.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
|
9
|
-
salabim-24.0.12.dist-info/top_level.txt,sha256=UE6zVlbi3F6T5ma1a_5TrojMaF21GYKDt9svvm0U4cQ,8
|
10
|
-
salabim-24.0.12.dist-info/RECORD,,
|
File without changes
|