Ausgabe der neuen DB Einträge
This commit is contained in:
parent
bad48e1627
commit
cfbbb9ee3d
2399 changed files with 843193 additions and 43 deletions
|
|
@ -0,0 +1 @@
|
|||
pip
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
Copyright (c) 2014
|
||||
Rackspace
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
@ -0,0 +1,487 @@
|
|||
Metadata-Version: 2.1
|
||||
Name: Automat
|
||||
Version: 20.2.0
|
||||
Summary: Self-service finite-state machines for the programmer on the go.
|
||||
Home-page: https://github.com/glyph/Automat
|
||||
Author: Glyph
|
||||
Author-email: glyph@twistedmatrix.com
|
||||
License: MIT
|
||||
Keywords: fsm finite state machine automata
|
||||
Platform: UNKNOWN
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 2
|
||||
Classifier: Programming Language :: Python :: 2.7
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.5
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Requires-Dist: attrs (>=19.2.0)
|
||||
Requires-Dist: six
|
||||
Provides-Extra: visualize
|
||||
Requires-Dist: graphviz (>0.5.1); extra == 'visualize'
|
||||
Requires-Dist: Twisted (>=16.1.1); extra == 'visualize'
|
||||
|
||||
|
||||
Automat
|
||||
=======
|
||||
|
||||
|
||||
.. image:: https://readthedocs.org/projects/automat/badge/?version=latest
|
||||
:target: http://automat.readthedocs.io/en/latest/
|
||||
:alt: Documentation Status
|
||||
|
||||
|
||||
.. image:: https://travis-ci.org/glyph/automat.svg?branch=master
|
||||
:target: https://travis-ci.org/glyph/automat
|
||||
:alt: Build Status
|
||||
|
||||
|
||||
.. image:: https://coveralls.io/repos/glyph/automat/badge.png
|
||||
:target: https://coveralls.io/r/glyph/automat
|
||||
:alt: Coverage Status
|
||||
|
||||
|
||||
Self-service finite-state machines for the programmer on the go.
|
||||
----------------------------------------------------------------
|
||||
|
||||
Automat is a library for concise, idiomatic Python expression of finite-state
|
||||
automata (particularly deterministic finite-state transducers).
|
||||
|
||||
Read more here, or on `Read the Docs <https://automat.readthedocs.io/>`_\ , or watch the following videos for an overview and presentation
|
||||
|
||||
Overview and presentation by **Glyph Lefkowitz** at the first talk of the first Pyninsula meetup, on February 21st, 2017:
|
||||
|
||||
.. image:: https://img.youtube.com/vi/0wOZBpD1VVk/0.jpg
|
||||
:target: https://www.youtube.com/watch?v=0wOZBpD1VVk
|
||||
:alt: Glyph Lefkowitz - Automat - Pyninsula #0
|
||||
|
||||
|
||||
Presentation by **Clinton Roy** at PyCon Australia, on August 6th 2017:
|
||||
|
||||
.. image:: https://img.youtube.com/vi/TedUKXhu9kE/0.jpg
|
||||
:target: https://www.youtube.com/watch?v=TedUKXhu9kE
|
||||
:alt: Clinton Roy - State Machines - Pycon Australia 2017
|
||||
|
||||
|
||||
Why use state machines?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Sometimes you have to create an object whose behavior varies with its state,
|
||||
but still wishes to present a consistent interface to its callers.
|
||||
|
||||
For example, let's say you're writing the software for a coffee machine. It
|
||||
has a lid that can be opened or closed, a chamber for water, a chamber for
|
||||
coffee beans, and a button for "brew".
|
||||
|
||||
There are a number of possible states for the coffee machine. It might or
|
||||
might not have water. It might or might not have beans. The lid might be open
|
||||
or closed. The "brew" button should only actually attempt to brew coffee in
|
||||
one of these configurations, and the "open lid" button should only work if the
|
||||
coffee is not, in fact, brewing.
|
||||
|
||||
With diligence and attention to detail, you can implement this correctly using
|
||||
a collection of attributes on an object; ``has_water``\ , ``has_beans``\ ,
|
||||
``is_lid_open`` and so on. However, you have to keep all these attributes
|
||||
consistent. As the coffee maker becomes more complex - perhaps you add an
|
||||
additional chamber for flavorings so you can make hazelnut coffee, for
|
||||
example - you have to keep adding more and more checks and more and more
|
||||
reasoning about which combinations of states are allowed.
|
||||
|
||||
Rather than adding tedious 'if' checks to every single method to make sure that
|
||||
each of these flags are exactly what you expect, you can use a state machine to
|
||||
ensure that if your code runs at all, it will be run with all the required
|
||||
values initialized, because they have to be called in the order you declare
|
||||
them.
|
||||
|
||||
You can read about state machines and their advantages for Python programmers
|
||||
in considerably more detail
|
||||
`in this excellent series of articles from ClusterHQ <https://clusterhq.com/blog/what-is-a-state-machine/>`_.
|
||||
|
||||
What makes Automat different?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
There are
|
||||
`dozens of libraries on PyPI implementing state machines <https://pypi.org/search/?q=finite+state+machine>`_.
|
||||
So it behooves me to say why yet another one would be a good idea.
|
||||
|
||||
Automat is designed around this principle: while organizing your code around
|
||||
state machines is a good idea, your callers don't, and shouldn't have to, care
|
||||
that you've done so. In Python, the "input" to a stateful system is a method
|
||||
call; the "output" may be a method call, if you need to invoke a side effect,
|
||||
or a return value, if you are just performing a computation in memory. Most
|
||||
other state-machine libraries require you to explicitly create an input object,
|
||||
provide that object to a generic "input" method, and then receive results,
|
||||
sometimes in terms of that library's interfaces and sometimes in terms of
|
||||
classes you define yourself.
|
||||
|
||||
For example, a snippet of the coffee-machine example above might be implemented
|
||||
as follows in naive Python:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class CoffeeMachine(object):
|
||||
def brew_button(self):
|
||||
if self.has_water and self.has_beans and not self.is_lid_open:
|
||||
self.heat_the_heating_element()
|
||||
# ...
|
||||
|
||||
With Automat, you'd create a class with a ``MethodicalMachine`` attribute:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from automat import MethodicalMachine
|
||||
|
||||
class CoffeeBrewer(object):
|
||||
_machine = MethodicalMachine()
|
||||
|
||||
and then you would break the above logic into two pieces - the ``brew_button``
|
||||
*input*\ , declared like so:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.input()
|
||||
def brew_button(self):
|
||||
"The user pressed the 'brew' button."
|
||||
|
||||
It wouldn't do any good to declare a method *body* on this, however, because
|
||||
input methods don't actually execute their bodies when called; doing actual
|
||||
work is the *output*\ 's job:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.output()
|
||||
def _heat_the_heating_element(self):
|
||||
"Heat up the heating element, which should cause coffee to happen."
|
||||
self._heating_element.turn_on()
|
||||
|
||||
As well as a couple of *states* - and for simplicity's sake let's say that the
|
||||
only two states are ``have_beans`` and ``dont_have_beans``\ :
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.state()
|
||||
def have_beans(self):
|
||||
"In this state, you have some beans."
|
||||
@_machine.state(initial=True)
|
||||
def dont_have_beans(self):
|
||||
"In this state, you don't have any beans."
|
||||
|
||||
``dont_have_beans`` is the ``initial`` state because ``CoffeeBrewer`` starts without beans
|
||||
in it.
|
||||
|
||||
(And another input to put some beans in:)
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.input()
|
||||
def put_in_beans(self):
|
||||
"The user put in some beans."
|
||||
|
||||
Finally, you hook everything together with the ``upon`` method of the functions
|
||||
decorated with ``_machine.state``\ :
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
||||
# When we don't have beans, upon putting in beans, we will then have beans
|
||||
# (and produce no output)
|
||||
dont_have_beans.upon(put_in_beans, enter=have_beans, outputs=[])
|
||||
|
||||
# When we have beans, upon pressing the brew button, we will then not have
|
||||
# beans any more (as they have been entered into the brewing chamber) and
|
||||
# our output will be heating the heating element.
|
||||
have_beans.upon(brew_button, enter=dont_have_beans,
|
||||
outputs=[_heat_the_heating_element])
|
||||
|
||||
To *users* of this coffee machine class though, it still looks like a POPO
|
||||
(Plain Old Python Object):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> coffee_machine = CoffeeMachine()
|
||||
>>> coffee_machine.put_in_beans()
|
||||
>>> coffee_machine.brew_button()
|
||||
|
||||
All of the *inputs* are provided by calling them like methods, all of the
|
||||
*outputs* are automatically invoked when they are produced according to the
|
||||
outputs specified to ``upon`` and all of the states are simply opaque tokens -
|
||||
although the fact that they're defined as methods like inputs and outputs
|
||||
allows you to put docstrings on them easily to document them.
|
||||
|
||||
How do I get the current state of a state machine?
|
||||
--------------------------------------------------
|
||||
|
||||
Don't do that.
|
||||
|
||||
One major reason for having a state machine is that you want the callers of the
|
||||
state machine to just provide the appropriate input to the machine at the
|
||||
appropriate time, and *not have to check themselves* what state the machine is
|
||||
in. So if you are tempted to write some code like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
if connection_state_machine.state == "CONNECTED":
|
||||
connection_state_machine.send_message()
|
||||
else:
|
||||
print("not connected")
|
||||
|
||||
Instead, just make your calling code do this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
connection_state_machine.send_message()
|
||||
|
||||
and then change your state machine to look like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.state()
|
||||
def connected(self):
|
||||
"connected"
|
||||
@_machine.state()
|
||||
def not_connected(self):
|
||||
"not connected"
|
||||
@_machine.input()
|
||||
def send_message(self):
|
||||
"send a message"
|
||||
@_machine.output()
|
||||
def _actually_send_message(self):
|
||||
self._transport.send(b"message")
|
||||
@_machine.output()
|
||||
def _report_sending_failure(self):
|
||||
print("not connected")
|
||||
connected.upon(send_message, enter=connected, [_actually_send_message])
|
||||
not_connected.upon(send_message, enter=not_connected, [_report_sending_failure])
|
||||
|
||||
so that the responsibility for knowing which state the state machine is in
|
||||
remains within the state machine itself.
|
||||
|
||||
Input for Inputs and Output for Outputs
|
||||
---------------------------------------
|
||||
|
||||
Quite often you want to be able to pass parameters to your methods, as well as
|
||||
inspecting their results. For example, when you brew the coffee, you might
|
||||
expect a cup of coffee to result, and you would like to see what kind of coffee
|
||||
it is. And if you were to put delicious hand-roasted small-batch artisanal
|
||||
beans into the machine, you would expect a *better* cup of coffee than if you
|
||||
were to use mass-produced beans. You would do this in plain old Python by
|
||||
adding a parameter, so that's how you do it in Automat as well.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.input()
|
||||
def put_in_beans(self, beans):
|
||||
"The user put in some beans."
|
||||
|
||||
However, one important difference here is that *we can't add any
|
||||
implementation code to the input method*. Inputs are purely a declaration of
|
||||
the interface; the behavior must all come from outputs. Therefore, the change
|
||||
in the state of the coffee machine must be represented as an output. We can
|
||||
add an output method like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.output()
|
||||
def _save_beans(self, beans):
|
||||
"The beans are now in the machine; save them."
|
||||
self._beans = beans
|
||||
|
||||
and then connect it to the ``put_in_beans`` by changing the transition from
|
||||
``dont_have_beans`` to ``have_beans`` like so:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
dont_have_beans.upon(put_in_beans, enter=have_beans,
|
||||
outputs=[_save_beans])
|
||||
|
||||
Now, when you call:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
coffee_machine.put_in_beans("real good beans")
|
||||
|
||||
the machine will remember the beans for later.
|
||||
|
||||
So how do we get the beans back out again? One of our outputs needs to have a
|
||||
return value. It would make sense if our ``brew_button`` method returned the cup
|
||||
of coffee that it made, so we should add an output. So, in addition to heating
|
||||
the heating element, let's add a return value that describes the coffee. First
|
||||
a new output:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.output()
|
||||
def _describe_coffee(self):
|
||||
return "A cup of coffee made with {}.".format(self._beans)
|
||||
|
||||
Note that we don't need to check first whether ``self._beans`` exists or not,
|
||||
because we can only reach this output method if the state machine says we've
|
||||
gone through a set of states that sets this attribute.
|
||||
|
||||
Now, we need to hook up ``_describe_coffee`` to the process of brewing, so change
|
||||
the brewing transition to:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
have_beans.upon(brew_button, enter=dont_have_beans,
|
||||
outputs=[_heat_the_heating_element,
|
||||
_describe_coffee])
|
||||
|
||||
Now, we can call it:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> coffee_machine.brew_button()
|
||||
[None, 'A cup of coffee made with real good beans.']
|
||||
|
||||
Except... wait a second, what's that ``None`` doing there?
|
||||
|
||||
Since every input can produce multiple outputs, in automat, the default return
|
||||
value from every input invocation is a ``list``. In this case, we have both
|
||||
``_heat_the_heating_element`` and ``_describe_coffee`` outputs, so we're seeing
|
||||
both of their return values. However, this can be customized, with the
|
||||
``collector`` argument to ``upon``\ ; the ``collector`` is a callable which takes an
|
||||
iterable of all the outputs' return values and "collects" a single return value
|
||||
to return to the caller of the state machine.
|
||||
|
||||
In this case, we only care about the last output, so we can adjust the call to
|
||||
``upon`` like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
have_beans.upon(brew_button, enter=dont_have_beans,
|
||||
outputs=[_heat_the_heating_element,
|
||||
_describe_coffee],
|
||||
collector=lambda iterable: list(iterable)[-1]
|
||||
)
|
||||
|
||||
And now, we'll get just the return value we want:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> coffee_machine.brew_button()
|
||||
'A cup of coffee made with real good beans.'
|
||||
|
||||
If I can't get the state of the state machine, how can I save it to (a database, an API response, a file on disk...)
|
||||
--------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
There are APIs for serializing the state machine.
|
||||
|
||||
First, you have to decide on a persistent representation of each state, via the
|
||||
``serialized=`` argument to the ``MethodicalMachine.state()`` decorator.
|
||||
|
||||
Let's take this very simple "light switch" state machine, which can be on or
|
||||
off, and flipped to reverse its state:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
class LightSwitch(object):
|
||||
_machine = MethodicalMachine()
|
||||
@_machine.state(serialized="on")
|
||||
def on_state(self):
|
||||
"the switch is on"
|
||||
@_machine.state(serialized="off", initial=True)
|
||||
def off_state(self):
|
||||
"the switch is off"
|
||||
@_machine.input()
|
||||
def flip(self):
|
||||
"flip the switch"
|
||||
on_state.upon(flip, enter=off_state, outputs=[])
|
||||
off_state.upon(flip, enter=on_state, outputs=[])
|
||||
|
||||
In this case, we've chosen a serialized representation for each state via the
|
||||
``serialized`` argument. The on state is represented by the string ``"on"``\ , and
|
||||
the off state is represented by the string ``"off"``.
|
||||
|
||||
Now, let's just add an input that lets us tell if the switch is on or not.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.input()
|
||||
def query_power(self):
|
||||
"return True if powered, False otherwise"
|
||||
@_machine.output()
|
||||
def _is_powered(self):
|
||||
return True
|
||||
@_machine.output()
|
||||
def _not_powered(self):
|
||||
return False
|
||||
on_state.upon(query_power, enter=on_state, outputs=[_is_powered],
|
||||
collector=next)
|
||||
off_state.upon(query_power, enter=off_state, outputs=[_not_powered],
|
||||
collector=next)
|
||||
|
||||
To save the state, we have the ``MethodicalMachine.serializer()`` method. A
|
||||
method decorated with ``@serializer()`` gets an extra argument injected at the
|
||||
beginning of its argument list: the serialized identifier for the state. In
|
||||
this case, either ``"on"`` or ``"off"``. Since state machine output methods can
|
||||
also affect other state on the object, a serializer method is expected to
|
||||
return *all* relevant state for serialization.
|
||||
|
||||
For our simple light switch, such a method might look like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.serializer()
|
||||
def save(self, state):
|
||||
return {"is-it-on": state}
|
||||
|
||||
Serializers can be public methods, and they can return whatever you like. If
|
||||
necessary, you can have different serializers - just multiple methods decorated
|
||||
with ``@_machine.serializer()`` - for different formats; return one data-structure
|
||||
for JSON, one for XML, one for a database row, and so on.
|
||||
|
||||
When it comes time to unserialize, though, you generally want a private method,
|
||||
because an unserializer has to take a not-fully-initialized instance and
|
||||
populate it with state. It is expected to *return* the serialized machine
|
||||
state token that was passed to the serializer, but it can take whatever
|
||||
arguments you like. Of course, in order to return that, it probably has to
|
||||
take it somewhere in its arguments, so it will generally take whatever a paired
|
||||
serializer has returned as an argument.
|
||||
|
||||
So our unserializer would look like this:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@_machine.unserializer()
|
||||
def _restore(self, blob):
|
||||
return blob["is-it-on"]
|
||||
|
||||
Generally you will want a classmethod deserialization constructor which you
|
||||
write yourself to call this, so that you know how to create an instance of your
|
||||
own object, like so:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@classmethod
|
||||
def from_blob(cls, blob):
|
||||
self = cls()
|
||||
self._restore(blob)
|
||||
return self
|
||||
|
||||
Saving and loading our ``LightSwitch`` along with its state-machine state can now
|
||||
be accomplished as follows:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> switch1 = LightSwitch()
|
||||
>>> switch1.query_power()
|
||||
False
|
||||
>>> switch1.flip()
|
||||
[]
|
||||
>>> switch1.query_power()
|
||||
True
|
||||
>>> blob = switch1.save()
|
||||
>>> switch2 = LightSwitch.from_blob(blob)
|
||||
>>> switch2.query_power()
|
||||
True
|
||||
|
||||
More comprehensive (tested, working) examples are present in ``docs/examples``.
|
||||
|
||||
Go forth and machine all the state!
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
../../../bin/automat-visualize,sha256=8iWWSqIUrhiegd0it0lFrwM-JuAtUvd7q5A8j70nvj8,263
|
||||
Automat-20.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
Automat-20.2.0.dist-info/LICENSE,sha256=siATAWeNCpN9k4VDgnyhNgcS6zTiPejuPzv_-9TA43Y,1053
|
||||
Automat-20.2.0.dist-info/METADATA,sha256=RlZub3EgNMk1YDCNYTDJ80ksrBRzPjgzVnYsLrS44nU,17919
|
||||
Automat-20.2.0.dist-info/RECORD,,
|
||||
Automat-20.2.0.dist-info/WHEEL,sha256=CihQvCnsGZQBGAHLEUMf0IdA4fRduS_NBUTMgCTtvPM,110
|
||||
Automat-20.2.0.dist-info/entry_points.txt,sha256=i4tDM5qwy3v1KIN7ETS2XRVcHkThhkq7ZFTPuyP6BpA,63
|
||||
Automat-20.2.0.dist-info/top_level.txt,sha256=vg4zAOyhP_3YCmpKZLNgFw1uMF3lC_b6TKsdz7jBSpI,8
|
||||
automat/__init__.py,sha256=ec8PILBwt35xyzsstU9kx8p5ADi6KX9d1rBLZsocN_Y,169
|
||||
automat/__pycache__/__init__.cpython-39.pyc,,
|
||||
automat/__pycache__/_core.cpython-39.pyc,,
|
||||
automat/__pycache__/_discover.cpython-39.pyc,,
|
||||
automat/__pycache__/_introspection.cpython-39.pyc,,
|
||||
automat/__pycache__/_methodical.cpython-39.pyc,,
|
||||
automat/__pycache__/_visualize.cpython-39.pyc,,
|
||||
automat/_core.py,sha256=IEtZHq3wsBZPX_VfMHMFy_uNjx1kfE11Qq-nmIXZe28,4819
|
||||
automat/_discover.py,sha256=ye7NHLZkrwYsPmBpTIyJuJ-VRCmwkOUpA0is-A81z04,4367
|
||||
automat/_introspection.py,sha256=i5UEGdj8lp2BnHnGeAyIwEyoN2gU1nXYg-ZPNX7oBbM,1274
|
||||
automat/_methodical.py,sha256=tvIQLMzMM1d6h_jUCQOM9zPJoGYYQZg0J5IkRszgjB0,15930
|
||||
automat/_test/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
automat/_test/__pycache__/__init__.cpython-39.pyc,,
|
||||
automat/_test/__pycache__/test_core.cpython-39.pyc,,
|
||||
automat/_test/__pycache__/test_discover.cpython-39.pyc,,
|
||||
automat/_test/__pycache__/test_methodical.cpython-39.pyc,,
|
||||
automat/_test/__pycache__/test_trace.cpython-39.pyc,,
|
||||
automat/_test/__pycache__/test_visualize.cpython-39.pyc,,
|
||||
automat/_test/test_core.py,sha256=CDmGBQNi9Pr7ZktfBcOhBvwI7wjLLYRtWZ0P5baXONY,2833
|
||||
automat/_test/test_discover.py,sha256=O9ndAdRAC8uO0uDhioz3e45EsJCF19jQZESj0RBC7ZM,21846
|
||||
automat/_test/test_methodical.py,sha256=t1CAKtT1fs-FoKMQxXl4ky6_6pgpG7lGDbyQrb_vIeo,18856
|
||||
automat/_test/test_trace.py,sha256=Mx1B8QgaE7QFk6blTie2j-Vx95hTV-zySnlxLalt8ek,3279
|
||||
automat/_test/test_visualize.py,sha256=8ErNYxovTiDyZkYkoP1BcyEazU_s0YQ3NHdfH9OihAg,13744
|
||||
automat/_visualize.py,sha256=jY8HkzaGdMoXB7LavvaneW4GdtBN6PRShl7-4OXDvss,6335
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.32.2)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py2-none-any
|
||||
Tag: py3-none-any
|
||||
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[console_scripts]
|
||||
automat-visualize = automat._visualize:tool
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
automat
|
||||
Loading…
Add table
Add a link
Reference in a new issue