automat

Self-service finite-state machines for the programmer on the go.

https://github.com/glyph/automat

Science Score: 26.0%

This score indicates how likely this project is to be science-related based on various indicators:

  • CITATION.cff file
  • codemeta.json file
    Found codemeta.json file
  • .zenodo.json file
    Found .zenodo.json file
  • DOI references
  • Academic publication links
  • Committers with academic emails
  • Institutional organization owner
  • JOSS paper metadata
  • Scientific vocabulary similarity
    Low similarity (12.7%) to scientific vocabulary

Keywords from Contributors

fuzzing attribution property-based-testing classes distribution pre-commit-hook gofmt formatter codeformatter autopep8
Last synced: 10 months ago · JSON representation

Repository

Self-service finite-state machines for the programmer on the go.

Basic Info
  • Host: GitHub
  • Owner: glyph
  • License: mit
  • Language: Python
  • Default Branch: trunk
  • Homepage:
  • Size: 580 KB
Statistics
  • Stars: 628
  • Watchers: 19
  • Forks: 68
  • Open Issues: 17
  • Releases: 0
Created almost 12 years ago · Last pushed 12 months ago
Metadata Files
Readme License Security

README.md

Automat

Documentation Status Build Status 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, or watch the following videos for an overview and presentation

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; hasWater, hasBeans, isLidOpen 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 more detail in this excellent article by Jean-Paul Calderone.

What makes Automat different?

There are dozens of libraries on PyPI implementing state machines. 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:

python class CoffeeMachine(object): def brewButton(self) -> None: if self.hasWater and self.hasBeans and not self.isLidOpen: self.heatTheHeatingElement() # ...

With Automat, you'd begin with a typing.Protocol that describes all of your inputs:

```python from typing import Protocol

class CoffeeBrewer(Protocol): def brewButton(self) -> None: "The user pressed the 'brew' button." def putInBeans(self) -> None: "The user put in some beans." ```

We'll then need a concrete class to contain the shared core of state shared among the different states:

```python from dataclasses import dataclass

@dataclass class BrewerCore: heatingElement: HeatingElement ```

Next, we need to describe our state machine, including all of our states. For simplicity's sake let's say that the only two states are noBeans and haveBeans:

```python from automat import TypeMachineBuilder

builder = TypeMachineBuilder(CoffeeBrewer, BrewerCore) noBeans = builder.state("noBeans") haveBeans = builder.state("haveBeans") ```

Next we can describe a simple transition; when we put in beans, we move to the haveBeans state, with no other behavior.

```python

When we don't have beans, upon putting in beans, we will then have beans

noBeans.upon(CoffeeBrewer.putInBeans).to(haveBeans).returns(None) ```

And then another transition that we describe with a decorator, one that does have some behavior, that needs to heat up the heating element to brew the coffee:

python @haveBeans.upon(CoffeeBrewer.brewButton).to(noBeans) def heatUp(inputs: CoffeeBrewer, core: BrewerCore) -> None: """ 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. """ print("Brewing the coffee...") core.heatingElement.turnOn()

Then we finalize the state machine by building it, which gives us a callable that takes a BrewerCore and returns a synthetic CoffeeBrewer

python newCoffeeMachine = builder.build()

```python

coffee = newCoffeeMachine(BrewerCore(HeatingElement())) machine.putInBeans() machine.brewButton() Brewing the coffee... ```

All of the inputs are provided by calling them like methods, all of the output behaviors are automatically invoked when they are produced according to the outputs specified to upon and all of the states are simply opaque tokens.

Owner

  • Name: Glyph
  • Login: glyph
  • Kind: user
  • Location: San Francisco Exclusion Zone

Founder of the Twisted project. Aspiring digital flâneur.

GitHub Events

Total
  • Create event: 8
  • Commit comment event: 6
  • Issues event: 3
  • Watch event: 36
  • Delete event: 2
  • Issue comment event: 9
  • Push event: 9
  • Pull request review event: 2
  • Pull request event: 14
  • Fork event: 3
Last Year
  • Create event: 8
  • Commit comment event: 6
  • Issues event: 3
  • Watch event: 36
  • Delete event: 2
  • Issue comment event: 9
  • Push event: 9
  • Pull request review event: 2
  • Pull request event: 14
  • Fork event: 3

Committers

Last synced: about 1 year ago

All Time
  • Total Commits: 438
  • Total Committers: 40
  • Avg Commits per committer: 10.95
  • Development Distribution Score (DDS): 0.247
Past Year
  • Commits: 172
  • Committers: 5
  • Avg Commits per committer: 34.4
  • Development Distribution Score (DDS): 0.029
Top Committers
Name Email Commits
Glyph c****e@g****m 330
Mark Williams m****s@g****m 35
Brian Warner w****r@l****m 14
fmoor f****r@g****m 8
Tom Marks t****s@g****m 4
FredInChina t****d@g****m 4
Moshe Zadka z****e@g****m 3
dependabot[bot] 4****] 2
Robert-André Mauchin z****m@g****m 2
John W. O'Brien j****n@s****m 2
Hugo h****k 2
Gábor Lipták g****k@g****m 2
Chelsea Winfree c****e@g****m 2
Alexander Duryagin a****n@g****m 2
Mikhail Terekhov t****v@e****m 1
Cory Dodt g****b@s****g 1
Alexander Shadchin s****n@y****m 1
Brian Dolbec d****n@g****g 1
Chris Mayo a****x@g****m 1
Chris Wolfe c****e@g****m 1
Zev Averbach y****s@z****s 1
Tristan Seligmann m****i@m****t 1
Tom Prince t****e@t****m 1
Ronny Pfannschmidt r****t@r****m 1
Mikhail Terekhov t****m@g****m 1
Mike Fiedler m****n@g****m 1
Kyle Altendorf s****a@f****t 1
Kevin Horn k****n@g****m 1
Jean-Paul Calderone e****n 1
James Hilliard j****1@g****m 1
and 10 more...

Issues and Pull Requests

Last synced: 10 months ago

All Time
  • Total issues: 53
  • Total pull requests: 70
  • Average time to close issues: over 2 years
  • Average time to close pull requests: about 2 months
  • Total issue authors: 34
  • Total pull request authors: 34
  • Average comments per issue: 2.23
  • Average comments per pull request: 2.04
  • Merged pull requests: 56
  • Bot issues: 0
  • Bot pull requests: 5
Past Year
  • Issues: 3
  • Pull requests: 11
  • Average time to close issues: less than a minute
  • Average time to close pull requests: 22 days
  • Issue authors: 3
  • Pull request authors: 5
  • Average comments per issue: 0.67
  • Average comments per pull request: 0.18
  • Merged pull requests: 7
  • Bot issues: 0
  • Bot pull requests: 5
Top Authors
Issue Authors
  • glyph (9)
  • markrwilliams (5)
  • tomprince (3)
  • ReblochonMasque (3)
  • moshez (3)
  • jackgeek (2)
  • tonnydourado (1)
  • eclipseo (1)
  • damaestro (1)
  • cjw296 (1)
  • ezaquarii (1)
  • twm (1)
  • hawkowl (1)
  • cwaldbieser (1)
  • RazvanLiviuVarzaru (1)
Pull Request Authors
  • glyph (21)
  • dependabot[bot] (5)
  • fmoor (5)
  • markrwilliams (4)
  • moshez (4)
  • cjmayo (2)
  • altendky (2)
  • ReblochonMasque (2)
  • eclipseo (2)
  • gliptak (2)
  • hynek (1)
  • shadchin (1)
  • tomdottom (1)
  • itamarst (1)
  • cjwatson (1)
Top Labels
Issue Labels
Pull Request Labels
dependencies (5) python (1)

Packages

  • Total packages: 5
  • Total downloads:
    • pypi 6,113,483 last-month
  • Total docker downloads: 21,863,583
  • Total dependent packages: 26
    (may contain duplicates)
  • Total dependent repositories: 2,839
    (may contain duplicates)
  • Total versions: 37
  • Total maintainers: 3
pypi.org: automat

Self-service finite-state machines for the programmer on the go.

  • Documentation: https://automat.readthedocs.io/
  • License: 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.
  • Latest release: 25.4.16
    published about 1 year ago
  • Versions: 14
  • Dependent Packages: 17
  • Dependent Repositories: 2,707
  • Downloads: 6,113,483 Last month
  • Docker Downloads: 21,863,583
Rankings
Downloads: 0.2%
Dependent repos count: 0.2%
Docker downloads count: 0.6%
Dependent packages count: 0.7%
Average: 1.6%
Stargazers count: 2.7%
Forks count: 5.5%
Maintainers (2)
Last synced: 10 months ago
proxy.golang.org: github.com/glyph/automat
  • Versions: 12
  • Dependent Packages: 0
  • Dependent Repositories: 0
Rankings
Stargazers count: 2.6%
Forks count: 3.2%
Average: 6.5%
Dependent packages count: 9.6%
Dependent repos count: 10.8%
Last synced: 11 months ago
spack.io: py-automat

Self-service finite-state machines for the programmer on the go.

  • Versions: 1
  • Dependent Packages: 1
  • Dependent Repositories: 0
Rankings
Dependent repos count: 0.0%
Stargazers count: 9.9%
Average: 13.0%
Forks count: 14.1%
Dependent packages count: 28.1%
Maintainers (1)
Last synced: 11 months ago
conda-forge.org: automat

Automat is a library for concise, idiomatic Python expression of finite-state automata (particularly deterministic finite-state transducers).

  • Versions: 5
  • Dependent Packages: 6
  • Dependent Repositories: 66
Rankings
Dependent repos count: 4.3%
Dependent packages count: 9.0%
Average: 13.8%
Stargazers count: 17.4%
Forks count: 24.4%
Last synced: 11 months ago
anaconda.org: automat

Automat is a library for concise, idiomatic Python expression of finite-state automata (particularly deterministic finite-state transducers).

  • Versions: 5
  • Dependent Packages: 2
  • Dependent Repositories: 66
Rankings
Dependent packages count: 20.4%
Dependent repos count: 22.0%
Average: 27.6%
Stargazers count: 30.6%
Forks count: 37.4%
Last synced: 11 months ago

Dependencies

setup.py pypi
  • attrs >=19.2.0
  • six *
.github/workflows/ci.yml actions
  • actions/checkout v3 composite
  • actions/setup-python v3 composite
  • codecov/codecov-action v3.1.0 composite