Salabim

Latest version: v25.0.8

Safety actively analyzes 723400 Python packages for vulnerabilities to keep your Python projects secure.

Scan your dependencies

Page 7 of 28

23.3.3

==========================

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.

23.3.2

==========================

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)

23.3.1

==========================

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)

23.3.0

==========================

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)

23.2.0

==========================

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)

23.1.4

==========================

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)
-----------

AnimateCombined did not handle a non list animation_objects parameter correctly. Fixed.
(bug reported by Michiel Luyken)

Bug fix (1)
-----------

Animated GIFs could not handle a transparent background color properly. Fixed.

Bug fix (2)
-----------

Under Python 3.10 (Pythonista only?) classes that have no __init__ method, don't seem to have a signature,
which lead to some problems in the aliasing of globals into Environment. Fixed.

Bug fix (3)
-----------

When using applying a filter for Store.from_store() the wrong component was returned. Fixed.
(bug reported by Martin Kunkel, fix slightly different)

Bug fix (4)
-----------

A bug in _AnimateIntro and _AnimateExtro made that Environment(isdefault_env=False) didn't work properly.
Fixed.
(bug reported by Michiel Luyken)

Bug fix (5)
-----------

Under Pythonista, the simulation time was not animated correctly in unsynced mode. Fixed.

HTML documentation readability enhancement (0)
----------------------------------------------

In the sidebar of the HTML documentation, level 4 items are now shown in a larger font,
which makes it easier to read.
(Inspired by a remark from Michiel Luyken)

Page 7 of 28

© 2025 Safety CLI Cybersecurity Inc. All Rights Reserved.