Hello community, here is the log from the commit of package python-transitions for openSUSE:Factory checked in at 2020-01-13 22:21:21 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-transitions (Old) and /work/SRC/openSUSE:Factory/.python-transitions.new.6675 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-transitions" Mon Jan 13 22:21:21 2020 rev:2 rq:763815 version:0.7.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-transitions/python-transitions.changes 2019-10-02 11:59:11.354986548 +0200 +++ /work/SRC/openSUSE:Factory/.python-transitions.new.6675/python-transitions.changes 2020-01-13 22:21:29.874517492 +0100 @@ -1,0 +2,8 @@ +Fri Jan 10 19:57:29 UTC 2020 - Martin Hauke <[email protected]> + +- Update to version 0.7.2 + * Fix transitions for enums with str behavior + * Don't mask away KeyError when executing a transition + * Add support for dynamic model state attribute + +------------------------------------------------------------------- Old: ---- transitions-0.7.1.tar.gz New: ---- transitions-0.7.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-transitions.spec ++++++ --- /var/tmp/diff_new_pack.XAI53h/_old 2020-01-13 22:21:30.638517847 +0100 +++ /var/tmp/diff_new_pack.XAI53h/_new 2020-01-13 22:21:30.638517847 +0100 @@ -1,6 +1,7 @@ # # spec file for package python-transitions # +# Copyright (c) 2020 SUSE LINUX GmbH, Nuernberg, Germany. # Copyright (c) 2019, Martin Hauke <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -18,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-transitions -Version: 0.7.1 +Version: 0.7.2 Release: 0 Summary: A lightweight, object-oriented Python state machine implementation License: MIT ++++++ transitions-0.7.1.tar.gz -> transitions-0.7.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/Changelog.md new/transitions-0.7.2/Changelog.md --- old/transitions-0.7.1/Changelog.md 2019-09-13 09:35:29.000000000 +0200 +++ new/transitions-0.7.2/Changelog.md 2020-01-10 08:51:20.000000000 +0100 @@ -1,5 +1,13 @@ # Changelog +## 0.7.2 (January 2020) + +Release 0.7.2 is a minor release and contains bugfixes and and a new feature + +- Bugfix #386: Fix transitions for enums with str behavior (thanks @artofhuman) +- Bugfix #378: Don't mask away KeyError when executing a transition (thanks @facundofc) +- Feature #387: Add support for dynamic model state attribute (thanks @v1k45) + ## 0.7.1 (September 2019) Release 0.7.1 is a minor release and contains several documentation improvements and a new feature: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/PKG-INFO new/transitions-0.7.2/PKG-INFO --- old/transitions-0.7.1/PKG-INFO 2019-09-13 09:49:33.000000000 +0200 +++ new/transitions-0.7.2/PKG-INFO 2020-01-10 09:41:44.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: transitions -Version: 0.7.1 +Version: 0.7.2 Summary: A lightweight, object-oriented Python state machine implementation. Home-page: http://github.com/pytransitions/transitions Author: Tal Yarkoni @@ -8,7 +8,7 @@ Maintainer: Alexander Neumann Maintainer-email: [email protected] License: MIT -Download-URL: https://github.com/pytransitions/transitions/archive/0.7.1.tar.gz +Download-URL: https://github.com/pytransitions/transitions/archive/0.7.2.tar.gz Description: ## Quickstart They say [a good example is worth](https://www.google.com/webhp?ie=UTF-8#q=%22a+good+example+is+worth%22&start=20) 100 pages of API documentation, a million directives, or a thousand words. @@ -278,6 +278,8 @@ Now, any time `lump` transitions to state `A`, the `on_enter_A()` method defined in the `Matter` class will fire. + #### <a name="checking-state"></a>Checking state + You can always check the current state of the model by either: - inspecting the `.state` attribute, or @@ -296,6 +298,15 @@ >>> 'solid' ``` + If you'd like you track it using a different attribute, you could do that using the `model_attribute` argument while initializing the `Machine`. + + ```python + lump = Matter() + machine = Machine(lump, states=['solid', 'liquid', 'gas'], model='matter_state', initial='solid') + lump.matter_state + >>> 'solid' + ``` + #### <a name="enum-state"></a>Enumerations So far we have seen how we can give state names and use these names to work with our state machine. If you favour stricter typing and more IDE code completion (or you just can't type 'sesquipedalophobia' any longer because the word scares you) using [Enumerations](https://docs.python.org/3/library/enum.html) might be what you are looking for: @@ -872,6 +883,20 @@ machine.add_model(Matter(), initial='liquid') ``` + Models with multiple states could attach multiple machines using different `model_attribute` values: + + ```python + lump = Matter() + + lump.state + >>> 'solid' + lump.shipping_state + >>> 'delivered' + + matter_machine = Machine(lump, model_attribute='state', **kwargs) + shipment_machine = Machine(lump, model_attribute='shipping_state', **kwargs) + ``` + ### Logging Transitions includes very rudimentary logging capabilities. A number of events – namely, state changes, transition triggers, and conditional checks – are logged as INFO-level events using the standard Python `logging` module. This means you can easily configure logging to standard output in a script: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/README.md new/transitions-0.7.2/README.md --- old/transitions-0.7.1/README.md 2019-09-13 09:35:29.000000000 +0200 +++ new/transitions-0.7.2/README.md 2020-01-10 09:27:35.000000000 +0100 @@ -1,10 +1,10 @@ # <a name="transitions-module"></a> transitions -[](https://github.com/pytransitions/transitions) +[](https://github.com/pytransitions/transitions) [](https://travis-ci.org/pytransitions/transitions) [](https://coveralls.io/github/pytransitions/transitions?branch=master) [](https://github.com/pytransitions/transitions) [](https://pypi.org/project/transitions) -[](https://github.com/pytransitions/transitions/compare/0.7.0...master) +[](https://github.com/pytransitions/transitions/compare/0.7.1...master) [](LICENSE) <!--[](Link)--> @@ -319,6 +319,8 @@ Now, any time `lump` transitions to state `A`, the `on_enter_A()` method defined in the `Matter` class will fire. +#### <a name="checking-state"></a>Checking state + You can always check the current state of the model by either: - inspecting the `.state` attribute, or @@ -337,6 +339,15 @@ >>> 'solid' ``` +If you'd like you track it using a different attribute, you could do that using the `model_attribute` argument while initializing the `Machine`. + +```python +lump = Matter() +machine = Machine(lump, states=['solid', 'liquid', 'gas'], model='matter_state', initial='solid') +lump.matter_state +>>> 'solid' +``` + #### <a name="enum-state"></a>Enumerations So far we have seen how we can give state names and use these names to work with our state machine. If you favour stricter typing and more IDE code completion (or you just can't type 'sesquipedalophobia' any longer because the word scares you) using [Enumerations](https://docs.python.org/3/library/enum.html) might be what you are looking for: @@ -913,6 +924,20 @@ machine.add_model(Matter(), initial='liquid') ``` +Models with multiple states could attach multiple machines using different `model_attribute` values: + +```python +lump = Matter() + +lump.state +>>> 'solid' +lump.shipping_state +>>> 'delivered' + +matter_machine = Machine(lump, model_attribute='state', **kwargs) +shipment_machine = Machine(lump, model_attribute='shipping_state', **kwargs) +``` + ### Logging Transitions includes very rudimentary logging capabilities. A number of events – namely, state changes, transition triggers, and conditional checks – are logged as INFO-level events using the standard Python `logging` module. This means you can easily configure logging to standard output in a script: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/tests/test_core.py new/transitions-0.7.2/tests/test_core.py --- old/transitions-0.7.1/tests/test_core.py 2019-08-27 11:10:23.000000000 +0200 +++ new/transitions-0.7.2/tests/test_core.py 2020-01-10 08:45:20.000000000 +0100 @@ -774,6 +774,13 @@ m = Machine(model=model) self.assertEqual(model.trigger(5), 5) + def raise_key_error(): + raise KeyError + + self.stuff.machine.add_transition('do_raises_keyerror', '*', 'C', before=raise_key_error) + with self.assertRaises(KeyError): + self.stuff.trigger('do_raises_keyerror') + def test_get_triggers(self): states = ['A', 'B', 'C'] transitions = [['a2b', 'A', 'B'], @@ -1009,6 +1016,45 @@ self.assertEqual(m.model.state, 'A') self.assertEqual(m.model.level, 2) + def test_dynamic_model_state_attribute(self): + class Model: + def __init__(self): + self.status = None + self.state = 'some_value' + + m = Machine(Model(), states=['A', 'B'], initial='A', model_attribute='status') + self.assertEqual(m.model.status, 'A') + self.assertEqual(m.model.state, 'some_value') + + m.add_transition('move', 'A', 'B') + m.model.move() + + self.assertEqual(m.model.status, 'B') + self.assertEqual(m.model.state, 'some_value') + + def test_multiple_machines_per_model(self): + class Model: + def __init__(self): + self.state_a = None + self.state_b = None + + instance = Model() + machine_a = Machine(instance, states=['A', 'B'], initial='A', model_attribute='state_a') + machine_a.add_transition('melt', 'A', 'B') + machine_b = Machine(instance, states=['A', 'B'], initial='B', model_attribute='state_b') + machine_b.add_transition('freeze', 'B', 'A') + + self.assertEqual(instance.state_a, 'A') + self.assertEqual(instance.state_b, 'B') + + instance.melt() + self.assertEqual(instance.state_a, 'B') + self.assertEqual(instance.state_b, 'B') + + instance.freeze() + self.assertEqual(instance.state_b, 'A') + self.assertEqual(instance.state_a, 'B') + class TestWarnings(TestCase): def test_warning(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/tests/test_enum.py new/transitions-0.7.2/tests/test_enum.py --- old/transitions-0.7.1/tests/test_enum.py 2019-08-26 11:21:40.000000000 +0200 +++ new/transitions-0.7.2/tests/test_enum.py 2019-12-25 13:40:10.000000000 +0100 @@ -47,6 +47,19 @@ assert m.is_YELLOW() is False assert m.is_GREEN() is True + def test_if_enum_has_string_behavior(self): + class States(str, enum.Enum): + __metaclass__ = enum.EnumMeta + + RED = 'red' + YELLOW = 'yellow' + + m = self.machine_cls(states=States, auto_transitions=False, initial=States.RED) + m.add_transition('switch_to_yellow', States.RED, States.YELLOW) + + m.switch_to_yellow() + assert m.is_YELLOW() is True + def test_property_initial(self): transitions = [ {'trigger': 'switch_to_yellow', 'source': self.States.RED, 'dest': self.States.YELLOW}, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/tox.ini new/transitions-0.7.2/tox.ini --- old/transitions-0.7.1/tox.ini 2019-09-13 09:35:29.000000000 +0200 +++ new/transitions-0.7.2/tox.ini 2020-01-10 08:58:18.000000000 +0100 @@ -1,5 +1,5 @@ [tox] -envlist = py27, py35, py36, py37, codestyle, check-manifest +envlist = py27, py35, py36, py37, py38, codestyle, check-manifest skip_missing_interpreters = True [testenv] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/transitions/core.py new/transitions-0.7.2/transitions/core.py --- old/transitions-0.7.1/transitions/core.py 2019-09-13 09:35:29.000000000 +0200 +++ new/transitions-0.7.2/transitions/core.py 2020-01-10 08:45:20.000000000 +0100 @@ -62,10 +62,10 @@ bool: True if a transitions has been conducted or the trigger event has been queued. """ try: - return machine.events[trigger_name].trigger(model, *args, **kwargs) + event = machine.events[trigger_name] except KeyError: - pass - raise AttributeError("Do not know event named '%s'." % trigger_name) + raise AttributeError("Do not know event named '%s'." % trigger_name) + return event.trigger(model, *args, **kwargs) def _prep_ordered_arg(desired_length, arguments=None): @@ -94,7 +94,7 @@ Attributes: name (str): State name which is also assigned to the model(s). on_enter (list): Callbacks executed when a state is entered. - on_exit (list): Callbacks executed when a state is entered. + on_exit (list): Callbacks executed when a state is exited. ignore_invalid_triggers (bool): Indicates if unhandled/invalid triggers should raise an exception. """ @@ -290,7 +290,7 @@ def _change_state(self, event_data): event_data.machine.get_state(self.source).exit(event_data) event_data.machine.set_state(self.dest, event_data.model) - event_data.update(event_data.model.state) + event_data.update(getattr(event_data.model, event_data.machine.model_attribute)) event_data.machine.get_state(self.dest).enter(event_data) def add_callback(self, trigger, func): @@ -408,7 +408,7 @@ """ Internal trigger function called by the ``Machine`` instance. This should not be called directly but via the public method ``Machine.trigger``. """ - state = self.machine.get_state(model.state) + state = self.machine.get_model_state(model) if state.name not in self.transitions: msg = "%sCan't trigger event %s from state %s!" % (self.machine.name, self.name, state.name) @@ -496,7 +496,7 @@ send_event=False, auto_transitions=True, ordered_transitions=False, ignore_invalid_triggers=None, before_state_change=None, after_state_change=None, name=None, - queued=False, prepare_event=None, finalize_event=None, **kwargs): + queued=False, prepare_event=None, finalize_event=None, model_attribute='state', **kwargs): """ Args: model (object or list): The object(s) whose states we want to manage. If 'self', @@ -570,6 +570,7 @@ self.after_state_change = after_state_change self.finalize_event = finalize_event self.name = name + ": " if name is not None else "" + self.model_attribute = model_attribute self.models = [] @@ -728,7 +729,10 @@ Returns: bool: Whether the model's current state is state. """ - return model.state == state + return getattr(model, self.model_attribute) == state + + def get_model_state(self, model): + return self.get_state(getattr(model, self.model_attribute)) def set_state(self, state, model=None): """ @@ -740,7 +744,7 @@ models = self.models if model is None else listify(model) for mod in models: - mod.state = state.value + setattr(mod, self.model_attribute, state.value) def add_state(self, *args, **kwargs): """ Alias for add_states. """ @@ -853,13 +857,15 @@ **kwargs: Additional arguments which can be passed to the created transition. This is useful if you plan to extend Machine.Transition and require more parameters. """ + if trigger == self.model_attribute: + raise ValueError("Trigger name cannot be same as model attribute name.") if trigger not in self.events: self.events[trigger] = self._create_event(trigger, self) for model in self.models: self._add_trigger_to_model(trigger, model) - if isinstance(source, string_types): - source = list(self.states.keys()) if source == self.wildcard_all else [source] + if source == self.wildcard_all: + source = list(self.states.keys()) else: source = [s.name if self._has_state(s) or isinstance(s, Enum) else s for s in listify(source)] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/transitions/extensions/diagrams.py new/transitions-0.7.2/transitions/extensions/diagrams.py --- old/transitions-0.7.1/transitions/extensions/diagrams.py 2019-08-26 11:21:40.000000000 +0200 +++ new/transitions-0.7.2/transitions/extensions/diagrams.py 2020-01-10 08:45:20.000000000 +0100 @@ -164,7 +164,7 @@ grph = self.graph_cls(self, title=title if title is not None else self.title) self.model_graphs[model] = grph try: - self.model_graphs[model].set_node_style(model.state, 'active') + self.model_graphs[model].set_node_style(getattr(model, self.model_attribute), 'active') except AttributeError: _LOGGER.info("Could not set active state of diagram") try: @@ -172,7 +172,7 @@ except KeyError: _ = self._get_graph(model, title, force_new=True) m = self.model_graphs[model] - m.roi_state = model.state if show_roi else None + m.roi_state = getattr(model, self.model_attribute) if show_roi else None return m.get_graph(title=title) def get_combined_graph(self, title=None, force_new=False, show_roi=False): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/transitions/extensions/markup.py new/transitions-0.7.2/transitions/extensions/markup.py --- old/transitions-0.7.1/transitions/extensions/markup.py 2019-08-26 11:21:40.000000000 +0200 +++ new/transitions-0.7.2/transitions/extensions/markup.py 2020-01-10 08:45:20.000000000 +0100 @@ -105,10 +105,10 @@ def _convert_models(self): models = [] - for m in self.models: - model_def = dict(state=m.state) - model_def['name'] = m.name if hasattr(m, 'name') else str(id(m)) - model_def['class-name'] = 'self' if m == self else m.__module__ + "." + m.__class__.__name__ + for model in self.models: + model_def = dict(state=getattr(model, self.model_attribute)) + model_def['name'] = model.name if hasattr(model, 'name') else str(id(model)) + model_def['class-name'] = 'self' if model == self else model.__module__ + "." + model.__class__.__name__ models.append(model_def) return models diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/transitions/extensions/nesting.py new/transitions-0.7.2/transitions/extensions/nesting.py --- old/transitions-0.7.1/transitions/extensions/nesting.py 2019-09-13 09:35:29.000000000 +0200 +++ new/transitions-0.7.2/transitions/extensions/nesting.py 2020-01-10 08:45:20.000000000 +0100 @@ -220,7 +220,7 @@ machine = event_data.machine model = event_data.model dest_state = machine.get_state(self.dest) - source_state = machine.get_state(model.state) + source_state = machine.get_model_state(model) lvl = source_state.exit_nested(event_data, dest_state) event_data.machine.set_state(self.dest, model) event_data.update(dest_state) @@ -245,13 +245,13 @@ """ An event type to work with nested states. """ def _trigger(self, model, *args, **kwargs): - state = self.machine.get_state(model.state) + state = self.machine.get_model_state(model) while state.parent and state.name not in self.transitions: state = state.parent if state.name not in self.transitions: msg = "%sCan't trigger event %s from state %s!" % (self.machine.name, self.name, - model.state) - if self.machine.get_state(model.state).ignore_invalid_triggers: + self.machine.get_model_state(model)) + if self.machine.get_model_state(model).ignore_invalid_triggers: _LOGGER.warning(msg) else: raise MachineError(msg) @@ -319,9 +319,9 @@ """ if not allow_substates: - return model.state == state_name + return getattr(model, self.model_attribute) == state_name - return self.get_state(model.state).is_substate_of(state_name) + return self.get_model_state(model).is_substate_of(state_name) def _traverse(self, states, on_enter=None, on_exit=None, ignore_invalid_triggers=None, parent=None, remap=None): @@ -515,6 +515,6 @@ state_name (str): Name of the destination state. """ - event = EventData(self.get_state(model.state), Event('to', self), self, + event = EventData(self.get_model_state(model), Event('to', self), self, model, args=args, kwargs=kwargs) - self._create_transition(model.state, state_name).execute(event) + self._create_transition(getattr(model, self.model_attribute), state_name).execute(event) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/transitions/version.py new/transitions-0.7.2/transitions/version.py --- old/transitions-0.7.1/transitions/version.py 2019-08-26 11:21:40.000000000 +0200 +++ new/transitions-0.7.2/transitions/version.py 2020-01-10 08:51:56.000000000 +0100 @@ -2,4 +2,4 @@ to determine transitions's version during runtime. """ -__version__ = '0.7.1' +__version__ = '0.7.2' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/transitions-0.7.1/transitions.egg-info/PKG-INFO new/transitions-0.7.2/transitions.egg-info/PKG-INFO --- old/transitions-0.7.1/transitions.egg-info/PKG-INFO 2019-09-13 09:49:33.000000000 +0200 +++ new/transitions-0.7.2/transitions.egg-info/PKG-INFO 2020-01-10 09:41:44.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: transitions -Version: 0.7.1 +Version: 0.7.2 Summary: A lightweight, object-oriented Python state machine implementation. Home-page: http://github.com/pytransitions/transitions Author: Tal Yarkoni @@ -8,7 +8,7 @@ Maintainer: Alexander Neumann Maintainer-email: [email protected] License: MIT -Download-URL: https://github.com/pytransitions/transitions/archive/0.7.1.tar.gz +Download-URL: https://github.com/pytransitions/transitions/archive/0.7.2.tar.gz Description: ## Quickstart They say [a good example is worth](https://www.google.com/webhp?ie=UTF-8#q=%22a+good+example+is+worth%22&start=20) 100 pages of API documentation, a million directives, or a thousand words. @@ -278,6 +278,8 @@ Now, any time `lump` transitions to state `A`, the `on_enter_A()` method defined in the `Matter` class will fire. + #### <a name="checking-state"></a>Checking state + You can always check the current state of the model by either: - inspecting the `.state` attribute, or @@ -296,6 +298,15 @@ >>> 'solid' ``` + If you'd like you track it using a different attribute, you could do that using the `model_attribute` argument while initializing the `Machine`. + + ```python + lump = Matter() + machine = Machine(lump, states=['solid', 'liquid', 'gas'], model='matter_state', initial='solid') + lump.matter_state + >>> 'solid' + ``` + #### <a name="enum-state"></a>Enumerations So far we have seen how we can give state names and use these names to work with our state machine. If you favour stricter typing and more IDE code completion (or you just can't type 'sesquipedalophobia' any longer because the word scares you) using [Enumerations](https://docs.python.org/3/library/enum.html) might be what you are looking for: @@ -872,6 +883,20 @@ machine.add_model(Matter(), initial='liquid') ``` + Models with multiple states could attach multiple machines using different `model_attribute` values: + + ```python + lump = Matter() + + lump.state + >>> 'solid' + lump.shipping_state + >>> 'delivered' + + matter_machine = Machine(lump, model_attribute='state', **kwargs) + shipment_machine = Machine(lump, model_attribute='shipping_state', **kwargs) + ``` + ### Logging Transitions includes very rudimentary logging capabilities. A number of events – namely, state changes, transition triggers, and conditional checks – are logged as INFO-level events using the standard Python `logging` module. This means you can easily configure logging to standard output in a script:
