forked from salabim/salabim
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathchangelog.txt
7181 lines (5802 loc) · 287 KB
/
changelog.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
salabim changelog
version 24.0.2 2024-03-15
==========================
Added functionality (0)
-----------------------
Salabim now also supports rounded rectangles, which can result in more pleasing animations.
Therefore, the spec argument (tuple) of sim.AnimateRectangle now has an optional fifth item,
which is the radius of the corners of the rounded rectangle.
The same holds for the rectangle0 and rectangle1 (tuple) paramaters of sim.Animate.
Note that if the radius is too big, the radius will be adjusted.
Changed functionality (0)
-------------------------
Under Pythonista, yieldless is False by default, now.
This can be useful for models which have no active components (and just env.run() statements).
Bug fix (0)
-----------
In version 23.3.12 the naming of components, queues, etc. was changed.
Unfortunately, the role of , and . at the end of the name were swapped.
From this version, the naming/sequence number system works again as intended and documented. So
for i in range(3):
car = Car('Audi.')
print(car.name(), car.sequence_number())
for i in range(3):
car = Car('BMW,')
print(car.name(), car.sequence_number())
will now (again) result in:
Audi.0 0
Audi.1 1
Audi.2 2
BMW.1 1
BMW.2 2
BMW.3 3
Bug fix (1)
-----------
Under PyPy yieldless did not work properly. Fixed.
Clarification (0)
-----------------
The salabim documentation states that models could run much faster under PyPy.
("We have found 6 to 7 times faster execution compared to CPython.")
In practice, the performance gain is much smaller. It is not uncommon that
models run even slower under PyPy!
Therefore, the paragraph about PyPy has been removed from the documentation.
(Inspired by a comment by Luc van den Brink)
Clarification (1)
-----------------
For the alternative UI the package PySimpleGUI is required.
Just recently, PySimpleGUI has changed its license to a more restrictive one.
And for commercial applications, charges apply.
If you want to use the real open-source version (which I recommend), please install
PySimpleGUI with
pip install PySimpleGUI==4.60.5
of course, this version is not maintained any more, but the package is rather stable.
I have also cloned the old PySimpleGUIfile repository to salabim, so you can just
copy pysimplegui.py (the only required file) from that repo to your model folder.
This information is also added to the documentation.
version 24.0.1 2024-01-11
==========================
New functionality (0)
---------------------
The method Environment.ui_granularity has been introduced.
With this, it is possible to set the number of simulation steps that have to be
called before _handle_ui_event is called (again).
This can significantly improve performance during simulation with animation off
and the UI shown.
The ui_granularity is 1 at start-up.
It might require some experimentation to find a suitable value:
- too low might result in slow execution
- too high might result in bad responsiveness
Enhancement (0)
---------------
Component.request() needed to have at least one resource specified.
From now on, the request method also works without any resource (tuple) specified. So
self.request()
is allowed, although it is just a dummy action, like self.hold(0).
Bug fix (0)
-----------
When passing (non-consumed) parameters to the Component.process method, an error was raised in
yieldless mode, so
class X(sim.Component):
def process(self, extra):
print(f"{extra=})
self.hold(1)
x = X(extra="extra")
didn't work properly in yieldless mode.
Fixed.
Bug fix (1)
-----------
In yieldless mode, the line number where a component becomes current,
sometimes incorrectly referred to a line in salabim, instead of the user program. Fixed.
Bug fix (2)
-----------
If ComponentGenerator was used with a spread (i.e. no iat) at a time not being 0,
an error was raised. Fixed.
Bug fix (3)
-----------
With blind_animation mode True, video production didn't work in yieldless mode. Fixed.
(Bug reported by max l)
version 24.0.0 2024-01-02
==========================
Added functionality (0)
-----------------------
The parameter 'interrupted' for Component.hold() has been introduced.
With this it is possible to hold a component, and let it go immediately in interrupted state.
This is very useful to simulate breakdowns, where a component should immediately observe
the breakdown state:
yield self.hold(10, interrupted=machine.mode() == "down")
This functionality would be rather difficult to implement, otherwise.
Note that the parameter 'interrupted' may be also an integer >=1 to denote the interrupt level.
Changed functionality (0)
-------------------------
For stability reasons, Component.interrupt() is from now on only allowed for scheduled components.
Added test (0)
--------------
A common mistake is to test the value of a monitor, like Component.mode or Component.status with
a string or integer.
E.g.
if comp.status == "passive":
...
In this case the test will always fail. Of course it should read:
if comp.status() == "passive":
...
From this version on, testing a monitor against anything else than a monitor will raise
a TypeError.
So, now
if comp.status == "passive":
...
will show:
TypeError: Not allowed to compare Monitor with str . Add parentheses?
version 23.3.13 2023-12-20
===========================
Bug fix (0)
-----------
When calling Component.from_store, the return value was incorrectly None when the request
could be honoured immediately.
Fixed.
(bug reported by Bart van Corven)
Bug fix (1)
-----------
Calling Environment.width() with adjust_x0_x1_y0=True didn't work properly. Fixed.
Bug fix (2)
-----------
Animating an animated gif or webp with AnimateImage(animation_repeat=True) caused a bug. Fixed.
Bug fix (3)
-----------
Calling Resource.release with a non anonymous resource caused an error. Fixed.
(bug reported by Floris Padt)
version 23.3.12 2023-11-28
===========================
Changed functionality (0)
-------------------------
In order to avoid excessive cache size, the sequence number is not cached anymore
for non-serialized names (those that do not end in "." or ",").
To the user that has the effect that calling sequence_number method on non-serialized
components, queues, monitors, resources, environment and states will always return 1.
In practice that means that:
man0 = Man(name="man")
man1 = Man(name="man")
print(man0.sequence_number(), man1.sequence_number())
will now print
1 1
,whereas that used to be
1 2
For
man0 = Man()
man1 = Man()
print(man0.sequence_number(), man1.sequence_number())
the output is still
1 2
Internally, neither the base_name nor the sequence_number are stored anymore
for non-serialized names, which reduces the memory footprint (marginally).
The documentation has been updated reflecting this change.
(inspired by an observation by Floris Padt)
Changed functionality (1)
-------------------------
In AnimateImage, a width of 0, resulted in a ValueError, caused by Pillow.
From now on, a width of 0, is accepted, which can be useful for
dynamic sizing of an image. So,
sim.AnimateImage("my_image.png", width=lambda t: sim.interpolate(t, 0, 10, 1024, 0))
will now result "nothing" after env.t() > 10.
Bug fix (0)
-----------
A bug caused a ValueError when tracing with suppress_trace_linenumbers(True) in yieldless mode. Fixed.
(bug reported by Ben Moverley Smith)
Bug fix (1)
-----------
For some reason, adding audio to a video file didn't work anymore (new version of ffmpeg?).
Fixed by adding the -safe 0 command to the final ffmpeg command.
version 23.3.11 2023-11-14
===========================
Changed functionality (0)
-------------------------
From now on, Monitor.print_statistics and Monitor.print_histogram does not show "no data"
anymore when the number of entries / total weight is zero. This change is made to be
have a more consistent output, which is important when post processing the output string.
In relation to this, histogram_autoscale now also returns 'sensible' values when
there are no entries or the total weight is zero.
Changed functionality (1)
-------------------------
When a component is cancelled, any claimed resources are now automatically released.
This is in line with the termination of a component.
(inspired by Luca Di Gaspero)
Extended functionality (0)
--------------------------
Under Windows, fonts are now also searched in the user/AppData/Local/Microsoft/Windows/Fonts
folder, as fonts are sometimes installed there as well.
Python in Excel functionality (0)
---------------------------------
In Python in Excel, line numbers are now completely suppressed in the trace.
The test for PythonInExcel has been changed (by testing whether __file__ is in globals())
to be compatible with the new runner functionality.
The file salabim.py now contains the line
# module = salabim
, to make it compatible with Python in Excel, out of the box.
Bug fix (0)
-----------
A problem with activating a process in yieldless mode fixed.
(Bug reported by bonusguy)
Bug fix (1)
-----------
A bug in Component.cancel() prevented a process to stop correctly in yieldless mode. Fixed.
(Bug reported by Devin Kain)
Bug fix (2)
-----------
A bug in Component.passivate(), Component.standby(), Component.from_store() and Component.to_store()
in yieldless mode.
When called one of these methods were applied on a component that's not current (so not self), the
process of that component stopped incorrectly. E.g.
other_car.passivate()
Fixed.
Documententation updates (0)
----------------------------
The documentation (both html and pdf) have been updated considerably, mainly as a result of
the preparation of the printed user and reference manual.
Availability of printed user and reference manual (0)
-----------------------------------------------------
Now a printed manual is available from your local Amazon site in two formats:
* full colour premium paper hardcover (ISBN 9798867009403)
* full colour standard paper paperback (ISBN 9798865131472)
Please search for "salabim user and reference manual" on your local Amazon site and you can buy it directly there.
version 23.3.10 2023-10-09
===========================
Added functionality (0)
-----------------------
Saving
an animated gif, png or webp file
a snapshot
under Python In Excel, now saves an encoded file to sim.pie_result().
The stored result contains the name of the file, so later decoding to a real file is possible.
Also, a file handler b64_file_handler is provided to allow writing to a file
in binary or text mode as an encoded file. This is used internally, but it can be used
by an application as well.
It is also possible to add text to the sim.pie_result() list without
affecting the stored file(s) information.
Note that for the decoding a VBA macro is required.
Changed functionality (0)
-------------------------
Under Python in Excel, blind_animation is enabled by default for a call to Environment().
Changed functionality (1)
-------------------------
If the trace had to show a line in the source of salabim (particularly in ComponentGenerator),
the line numbers were not always displayed correctly and were not very useful
for the trace anyway.
From now on, in that case, no line number will be shown.
Bug fix (0)
-----------
Label lines in AnimateMonitor / Monitor.animate() were obscured by the fillcolor.
From now on, the line around the frame will be shown over the label lines,
whereas the label lines will be shown over the filled rectangle.
Bug fix (1)
-----------
On Pythonista, the fallback font did not work properly as Pythonista does not support
file handles as the font parameter for PIL.ImageFont. Therefore, on this platform
salabim falls back on the standard Arial font.
Bug fix (2)
-----------
Pause/Resume an animation with <space> didn't work properly. Fixed.
(bug reported by Harald Mutzke)
Type annotation fix (0)
-----------------------
Fixed a wrong type annotation in AnimateSlider.
(flagged by Harald Mutzke)
PyPI/GitHub distribution change (0)
------------------=-----------------
On PyPI salabim now has a meaningful description.
GitHub also has an updated readme.
version 23.3.9 2023-09-18
==========================
New functionality (0)
---------------------
A new context manager sim.capture_stdout(), makes it possible to capture all stdout output.
Unless include_print=False is given, the output *also* goes to the console (as usual).
For example, with
with sim.capture_stdout():
env = sim.Environment(trace=True)
all trace output will be printed AND be captured.
With
with sim.capture_stdout(include_print=False):
env = sim.Environment(trace=True)
, trace output will not be printed, but still be captured.
The captured output can be retrieved with
sim.captured_stdout_as_list() to retrieve it as a list of strings
sim.captured_stdout_as_str() to retrieve it as a string
sim.captured_stdout_as_file() to retrieve it in a file (given as a str, Path or file handle)
The first function is particularly useful for Python in Excel.
It is possible to clear the captured_stdout information with
sim.clear_captured_stdout()
Of course, we can also use env.capture_stdout(), env.captured_stdout_to_list(), etc. instead.
New functionality (1)
---------------------
Salabim can now run under Python in Excel.
This required a change in the line number assessment.
When the line cannot be determined, a question mark will now be used instead.
Note that only blind animation is supported as tkinter is not available under
Python in Excel.
Although technically salabim supports making an animated Gif under Python in Excel (with
some specialized VBA code), this is not very practical (as of now).
Changed functionality (0)
-------------------------
The salabim code now contains encoded versions of the fonts
"calibri" / "std" / ""
"dejavusansmono" / "mono"
"mplus_1m_regular" / "narrow"
This means that it is not longer required to have the files
calibri.ttf
DejaVuSansMono.ttf
mplus-1m-regular.ttf
installed or available anywhere anymore.
Also, when a font is not found, salabim will fall back to the calibri font.
This makes distributing models without installing salabim simpler.
And it also makes font handling available to models run under PythonInExcel.
Changed functionality (1)
-------------------------
AnimateQueue() / Queue.animate() now has a screen_coordinates parameter that is True by default.
If the animation objects of the components to be shown are in user coordinates, specify screen_coordinates=False.
Actually, this change was already introduced in salabim 23.3.5, but was left out of the changelog of that version.
Bug fix (0)
-----------
The patch in salabim 23.3.5 to support Pillow 10.0.0, did not work under all circumstances.
Fixed.
Bug fix (1)
-----------
Blind animation still required tkinter under some circumstances. Fixed.
Bug fix (2)
-----------
Blind animation video making did not finish when env.run() was specified. Fixed.
Bug fix (3)
-----------
AnimateMonitor() / Monitor.animate() label lines did not observe the xy_offset parameter. Fixed.
AnimateMonotor() / Monitor.animate() label lines could 'override' the surrounding rectangle. Fixed.
Bug fix (4)
-----------
AnimateText did not observe the offsetx and offsety parameter correctly. Fixed.
version 23.3.8 2023-09-05
==========================
Enhanced UI functionality (0)
-----------------------------
The UI window layout has been changed to be more useful with
narrower windows.
Some more updates to the appearance.
When the UI is started, the time in the animation window is no longer disabled.
The user can always switch that off with Environment.show_time(False).
Environment.start_ui() now has useful defaults for window_size and window_position.
Environment.start_ui() now has a parameter default_actions, which is True by default.
If False, there are no actions like, pause/go, speed, etc. defined, so the user has to
specify the required actions with the actions parameter.
This is useful to use a different layout or leave out certain elements. Be sure to
use the same keys to be able to use the programmed interactions. However, you
can leave out elements.
It is recommended to use the standard actions as a template:
[sg.Text("", key="-TIME-", metadata=[1, 2], size=200)],
[sg.Button("Pause", key="-PAUSE-GO-", metadata=[1, 2]), sg.Button("Stop", key="-STOP-", button_color=("white", "firebrick3"), metadata=[1, 2])],
[sg.Checkbox("Pause at each step", False, key="-PAUSE-AT-EACH-STEP-", enable_events=True, metadata=[1, 2])],
[sg.Text(f"Pause at{env.get_time_unit(template='(t)')}", key="-PAUSE-AT-TEXT-", size=17), sg.Input("", key="-PAUSE-AT-", size=(10, 20))],
[sg.Text(f"Pause each{env.get_time_unit(template='(d)')}", key="-PAUSE-EACH-TEXT-", size=17), sg.Input("", key="-PAUSE-EACH-", size=(10, 20))],
[
sg.Text("Speed", key="-SPEED-TEXT-", metadata=[1]),
sg.Button("/2", key="-SPEED/2-", metadata=[1]),
sg.Button("*2", key="-SPEED*2-", metadata=[1]),
sg.Input("", key="-SPEED-", size=(7, 10)),
],
[sg.Checkbox("Trace", env.trace(), key="-TRACE-", metadata=[1, 2], enable_events=True)],
[sg.Checkbox("Synced", env.synced(), key="-SYNCED-", metadata=[1], enable_events=True)],
[sg.Checkbox("Animate", True, key="-ANIMATE-", metadata=[1, 2], enable_events=True)],
The simulation did not stop exactly at the time given in 'Pause at'. Fixed.
Added demos (0)
---------------
The program demo_ui.py shows a pretty standard UI with some extra elements.
The program demo_horizontal_ui.py demonstrates the same functionality, but now
with a horizontal UI window. Note that this requires quite a bit more
code than the standard one.
But it demonstrates what is possible.
Bug fix (0)
-----------
Component.to_store_store did not always return the right store. Fixed.
Thanks to Florian Förster for reporting this bug and the fix.
Bug fix (1)
-----------
Store.to_store_requesters() returned the wrong queue. Fixed.
version 23.3.7 2023-08-22
==========================
Bug fix (0)
-----------
Environment.paused(True) did not call set_start_animation(), which is required. Fixed.
Bug fix (1)
-----------
Removing and showing an animated monitor did not restore the labels and label lines. Fixed.
version 23.3.6 2023-08-18
==========================
New functionality (0)
---------------------
The parameter datetime0 in Environment(), may now be also a string, which is relatively
free format as it uses dateutil.parser.parse.
Note that (unless Environment.dateutil_parse is overridden), it is advised to use
Y-M-D format, e.g.
env = sim.Environment(datetime0="2023-08-17")
Note that for this functionality, dateutil has to be installed, most likely with
pip install python-dateutil
New functionality (1)
---------------------
The parameter datetime0 in Environment.datetime0(), may now be also a string, which is relatively
free format as it uses dateutil.parser.parse.
Note that (unless Environment.dateutil_parse is overridden), it is advised to use
Y-M-D format, e.g.
env.datetime0("2023-08-17")
Note that for this functionality, dateutil has to be installed, most likely with
pip install python-dateutil
New functionality (2)
---------------------
The above functionality uses a method Environment.dateutil_parse, which more or less defaults to
def dateutil_parse(self, spec):
import dateutil.parser
return dateutil.parser.parse(spec, dayfirst=False, yearfirst=True)
If other values for dayfirst or yearfirst are desired, formulate a custom method, like
sim.Environment.dateutil_parse = lambda self, spec: dateutil.parser.parse(spec, dayfirst=True, yearfirst=False)
Refer to the Python dateutil.parse documentation for details.
Note that for this functionality, dateutil has to be installed, most likely with
pip install python-dateutil
Changed functionality (3)
-------------------------
If datetime0 is not False, all process interaction methods that require a time, like Component.hold,
Component creation, fail_at parameters, can now be a datetime.datetime, e.g.
comp.hold(till=datetime.datetime(year=2023, month=8, day=17))
Or it can be string containing a relatively free format date, like
comp.hold(till="2023-08_07")
And now it is even possible to use a string:
comp.hold(till="1000")
If datetime0 is not False, all process interaction methods that require a duration, like Component.hold,
Component creation, fail_delay parameters, can now be a datetime.timedelta, e.g.
comp.hold(datetime.timedelta(hours=1)
Vehicle(delay=datetime.timedelta(days=2))
Or it can be string containing a relatively free format duration, like
comp.hold("12:00:00"))
And now it is even possible to use a string:
comp.hold("1000")
Of course, these parameters can also be a callable, like
comp.hold(env.Pdf(("12:00", "13:45", "20:30"), 1))
Note that this functionality is a by-product of the implementation of the not yet documented, but already
available, UI (using PySimpleGUI) functionality.
New functionality (4)
---------------------
The value of State.value can now be assigned and queried directly. E.g.
my_state.value.value = 3
print(my_state.value.value)
is equivalent to
my_state.set(3)
print(my_state.get())
This can be useful to increment or decrement a state. E.g.
my_state.value.value += 5
is equivalent to
my.state.set(my_state.get() + 5)
The value of Component.mode can now be assigned also like:
my_component.mode.value = "working"
, instead of
my_component.set_mode("working")
This can also be useful to increment or decrement a mode. E.g.
my_component.mode.value += 5
is equivalent to
my_component.set_mode(my_component.mode() + 5)
Changed functionality (0)
-------------------------
The class Environmnent does not contain a subclass Environment anymore,
so you can't say
env1 = env.Environment()
anymore. This was never intended to be supported.
Use
env1 = sim.Environment()
now.
Compatibility fix (0)
---------------------
When saving a video as .gif, Pythonista required the images2gif module, which has a bug in
the latest version of Pythonista.
As Pythonista has now an updated version of Pillow, saving can and will be done in the same way as
in non Pythonista versions.
version 23.3.5 2023-07-29
==========================
Compatibility update (0)
------------------------
Due to a change in Pillow 10.0.0, salabim did not work properly with that version:
- font.getsize was deprecated. Salabim now uses font.getbbox.
- Image.ANTIALIAS was deprecated. Salabim now uses Image.LANCZOS
From now on, Pillow >=10.0.0 is also supported.
version 23.3.4 2023-07-26
==========================
Bug fix (0)
-----------
A bug in Component.to_stock() fixed.
version 23.3.3 2023-07-23
==========================
Changed functionality (0)
-------------------------
In order to check whether a model that runs with sim.yieldless(False)
is not a yieldless model, salabim may under rare circumstances report:
ValueError: process must be a generator (contain yield statements.)
Maybe this a yieldless model. In that case:
- remove sim.yieldless(False)
If it is indeed a yield model, make this process method (and maybe others) into a generator, e.g.
by adding at the end:
return
yield # just to make this a generator
So when it is indeed a yieldless model, remove the sim.yieldless(False) statement.
If this is a model with yields, change the process method into a generator, e.g. by adding
yield self.hold(0) # added to make this process a generator
or
if False:
yield # added to make this process a generator
or (at the end)
return
yield # added to make this process a generator
Added functionality (0)
-----------------------
The method Store.to_store_requesters() returns a reference to the to requesters, like
Store.from_requesters() that was already in salabim.
These methods can be very useful for animating a store.
Bug fix (0)
-----------
AnimateGrid used 0 and env.width() for the x-range. And 0 and env.height() for the y-range.
This worked fine as long as screen coordinates were the same as user coordinates.
In order to properly work with user coordinates, the x-range should be env.x0() and env.x1()
and the y-range should be env.y0() and env.y1(). Fixed.
version 23.3.2 2023-07-10
==========================
Bug fix (0)
-----------
Please note that
When another component than self was used in activate, passivate, hold (or any process interaction)
it was not possible to use yield. So
yield other.activate()
was not executed properly, although it did not raise an (immediate) error.
From now on, this is accepted, which makes it also easier to translate yieldless models to not yieldless models,
as the user can just add yield for any process interaction call.
is not valid anymore as the implementation contained a serious bug. Fixed.
To summarize (only relevant for yield versions):
other.activate(), other.hold(), etc should NEVER be called with as yield other.activate(), yield other.hold(), etc.
when other is not self!
(bug reported by Michiel Luyken)
version 23.3.1 2023-07-10
==========================
Bug fix (0)
-----------
As mentioned in the 23.3.0 changelog, yieldless should be True by default.
But yieldless was False. Fixed.
To avoid any confusion: salabim runs now in yieldless mode by default!
Bug fix (1)
-----------
A bug in Component.from_store caused that the component reported failed. Fixed.
(bug reported by Michiel Luyken)
version 23.3.0 2023-07-09
==========================
Changed default mode (0)
------------------------
From now on, yieldless is the default mode.
For non yieldless (yield) models to run you can
- add sim.yieldless(False), just after import salabim as sim or
- add the yieldless parameter to env = sim.Environment, like
env = sim.Environment(trace=True, yieldless=False) or
- remove all yield statements or
- run salabim_unyield.py over the required model(s)
The documentation now also defaults to the yieldless version.
Improved functionality in yield mode (0)
----------------------------------------
When another component than self was used in activate, passivate, hold (or any process interaction)
it was not possible to use yield. So
yield other.activate()
was not executed properly, although it did not raise an (immediate) error.
From now on, this is accepted, which makes it also easier to translate yieldless models to not yieldless models,
as the user can just add yield for any process interaction call.
Related to this is a much more useful error message when a yield model is run in yieldless mode.
Improved documentation (0)
--------------------------
Salabim now has two complete sets of documentation: for yieldless (default) and yield version.
There are also two versions of the pdf documentation.
sample models and sample 3d models (0)
--------------------------------------
The GitHub repository now features the yieldless versions. The non yieldless (yield) versions
end with _yield.
Bug fix (0)
-----------
When a queue element was selected by subscripting, like my_queue[index], None was returned
when the index was out of range. Example my_queue[0] result is None, when my_queue is empty.
This should raise an IndexError. Fixed.
(inspired by a problem reported by Michiel Luyken)
version 23.2.0 2023-07-02
==========================
Completely new way of building processes (0)
--------------------------------------------
With this version comes a completely new way to build processes.
Up to now, a Component's process was essentially a generator with yields to allow
switching to other Components. Those yields are far from natural and often caused
beginners (and sometimes experts) to make mistakes.
And last but not least, if you wanted a specific task to be called as a method,
you had to use 'yield from', which is a confusing concept to say the least.
Therefore, from now on the process interaction may be done with so-called greenlets.
If you specify
sim.yieldless(True)
prior to any sim.Environment call, salabim works differently, as you can and should
refrain from the yield part.
So,
def double_hold(self, duration):
yield self.hold(2 * duration)
def process(self):
yield self.hold(5)
while not len(q):
yield self.passivate()
other.activate()
yield from self.double_hold(4)
item = yield self.from_store(store)
, now reads:
def double_hold(self, duration):
self.hold(2 * duration)
def process(self):
self.hold(5)
while not len(q):
self.passivate()
other.activate()
self.double_hold(4)
item = self.from_store(store)
Wow! So much cleaner.
There's just one caveat: the code might run slower, although in practice not that much.
But that's just a small price for a much cleaner API.
For now, salabim offers both ways of defining processes, where coroutines (with yields) are
still the default. However, that might change in the future. The same holds for the documentation
and sample scripts.
In order to run without yields, you can just do
sim.yieldless(True)
before calling env = sim.Environment(), or do
env = sim.Environment(yieldless=True)
Anyway, in that case the greenlet module has to be installed, most likely with:
pip install greenlet
Note that this yieldless=True functionality is still experimental. Please report any bugs or
strange behaviour.
In order to facilitate the conversion to yieldless=True, there's a script to do just that:
salabim_unyield.py
, which is a bit more intelligent than just removing the text 'yield' and 'yield from'.
New functionality (0)
---------------------
The method Component.from_store has a new parameter: key.
If present, it should be function accepting a component and returning a value that can be compared
to others, most likely a number or string.
When applied, the component with the lowest key (and meeting the filter) will be returned, if any.
(inspired by a request of Zhong Zhyu)
New functionality (1)
---------------------
Introduced sim.AnimateGrid/env.AnimateGrid, which can be useful to align animation objects.
The function will draw a grid with a given spacing and add text labels, like:
env.AnimateGrid(spacing=100, linecolor="blue")
or
env.AnimateGrid(spacing=100, linecolor="black", textcolor="black", visible=preview_mode)
(inspired by a request of Michiel Luyken and a reference implementation by Richard)
New functionality (2)
---------------------
From this version, an alternative user interface (UI) via PySimpleGUI is available.
This makes it easier to control animations and simulations via a separate window.
In the new control window the aplication can add widgets, including input, buttons,
radio buttons, sliders, ...
It is now also possible to turn of animation up to a certain time (including
at regular intervals) and regain control.
This feature is not yet documented and still experimental.
However, you can experiment with it. See sample models/demo_ui.py in the github
repository.
Functionality change (0)
------------------------
The attribute Environment.paused is now a method that can be used to set and get the value
of the internal paused status.
This can affect previous models that explicitely wrote or read the attribute env.paused.
This for instance means that
self.paused = True
has to be changed into
self.paused(True)
Likewise
if self.paused:
has to be changed into
if self.paused():
USERS WHO HAVE PREVIOUSLY USED env.paused SHOULD CHECK AND CHANGE THEIR CODE !
Enhancement (0)
---------------
sim.linspace / env.linspace did not have a default for the num parameter.
From this version on the default is 50 (as in numpy.linspace).
Documentation / docstring update (0)
------------------------------------
The layer parameter for Animatexxx classes was missing in the docstring. Fixed.
Also, a section on Using layers is added to the Animation chapter of the documentation.
Bug fix (0)
-----------
When using sim.Animate(image=) / env.Animate(image=), the animation crashed
because the various new image parameters
flip_horizontal, flip_vertical, animation_start, animation_speed,
animation_repeat, animation_pingpong, animation_from and animation_to
were not implemented at all. Fixed.
Bug fix (1)
-----------
When an unexpected keyword was given in any 'step' method (hold, activate, ...),
the process was incorrectly terminated without any warning.
Fixed.
Bug fix (2)
-----------
In AnimateImage, filename that contained // was incorrectly always opened as a URL.
Thus not correctly handling files like C://test//abc.jpg, although these are
valid file names. Fixed.
(Inspired by a problem reported by Harald Mutzke)
Bug fix (3)
-----------
If simulation events happened after the current animation time (env.t()), salabim did
'rewind' the animation time, thus causing unwanted behaviour.
Fixed.
(bug reported by Richard)
version 23.1.4 2023-05-14
==========================
New functionality (0)
---------------------
Introduced sim.full_screen() / env.full_screen() , which
creates a true full screen window, without a title, where
x0=0, y0=0, x1=width of screen
(Inspired by a remark from Lukas Hollenstein)
New parameter (0)
-----------------
The method sim.width() / env.width() now have a second parameter
adjust_x0_x1_y0, which is False by default.
If adjust_x0_x1_y0 is True, apart from setting the width,
x0 will be set to 0, y0 will be set to 0 and x1 will be set to the given width.
E.g.
env.width(1000, True)
Note that existing programs won't be affected, as the parameter
adjust_x0_x1_y0 is False by default.
New functionality (1)
---------------------
sim.AnimateImage / env.AnimateImage now supports animated GIFs and
animated .webp files.
Therefore, AnimateImage has six new parameters:
- animation_start (simulation) time that the animation should start
- animation_repeat if False (default) no repeat, if True, repeat
- animation_pingpong if False (default) no pingpong, if True, first goes forward then backward
- animation_speed specifies how fast the animation should be (relative to env.speed)
- animation_from specifies the time in the video from which to animate
- animation_to specifies the time in the video to which to animate
Note that these parameters may be specified for non animated images as well,
but will have no meaning, then.
All these parameters are dynamic.
The AnimateImage now has a method duration that returns the duration of the image
(0 if not animated).
Note that animated GIFs and .webp files can have a transparent background,
which makes it ideal for showing moving objects, like vehicles, cranes, animals, etc.
New functionality (2)
---------------------
It is now possible to produce .webp format videos.
E.g.
with env.video("my_video.webp"):
env.run(10)
New functionality (3)
---------------------
The class sim.AnimateImage / env.AnimateImage can now be used with
.webp files (still or animated).
E.g.
env.AnimateImage(image="my_picture.webp")
New functionality (4)
---------------------
The class sim.AnimateImage / env.AnimateImage can now be used also to
animate an image given by a URL.
Any image parameter that contains // will be opened as a URL.
E.g.
env.AnimateImage("https://salabim.org/manual/_images/2d1.gif")
New functionality (5)
---------------------
The class sim.AnimateImage / env.AnimateImage now have two new (dynamic)
boolean parameters:
- flip_horizontal
- flip_vertical
Both parameters are False by default.
When True, the image is flipped either horizontal or vertical.
Note that this functionality is also available for animated
images.
E.g.
env.AnimateImage("mypicture.webp", flip_vertical=lambda t: t > 10)
New functionality (6)
---------------------
The new function sim.video_duration() / method env.video_duration()
will return the length or a given animated GIF/Webp file or URL.
This can be useful in animating a GIF/Webp file or URL.
E.g.
duration = env.video_duration("my_video.gif")
New functionality (7)
---------------------
ComponentGenerator has a new parameter: at_end. If not specified, no action when the component generator ends.
If a parameterless function is specified, this function will be called when the component generator ends.
The most obvious usage of this is to reactivate main when all components are generated.
ComponentGenerator(number=10, iat=env.Uniform(1,2), at_end=lambda: env.main().activate())
Performance improvement (0)
---------------------------
When using AnimateImage, all images are now properly cached, which improves
performance under certain conditions.
Support for Pythonista 3.4 (0)
------------------------------
Fixed a problem in the set_aliases routine.
A bug in Pythonista 3.4 makes that the using the Calibri font with fontsize between 12 and 17 crashes the
system. Therefore, on Pythonista, Calibri font is replaced by the Arial font, until the Pythonista bug
is fixed.
Bug fix (0)
-----------