{ "info": { "author": "Anders Eurenius", "author_email": "aes@spotify.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Programming Language :: Python", "Topic :: Software Development :: Testing" ], "description": ".. -*- mode: rst -*-\n\n==================\nPython Graphwalker\n==================\n\n\nIntro\n=====\nPython-Graphwalker is a tool for testing based on finite state machine graphs.\nGraphwalker reads FSMs specified by graphs, plans paths, calls model methods\nby name from graph labels and reports progress and results.\n\nWhile conceptually derived from the Graphwalker project, (implemented in java)\nthis is a complete reimplementation from that initial concept.\n\nNotably, there are a few differences:\n\n* In the original, nodes are considered states to be verified and edges\n actions to be taken, but this version has no ambition to enforce this\n convention in any way, even though it is quite useful.\n\n* Python Graphwalker does not understand extended FSM labels. It should ignore\n them, but proceed at your own risk until this is definitively dealt with one\n way or the other.\n\n* Python Graphwalker is quite promiscuous about letting you load and combine\n code to implement the different components of the design. Some combinations\n don't make sense.\n\n\n.. figure:: graphwalker/test/examples/selftest.png\n\n The graph for the self-test of the Interactive planner.\n\n\nOverall design\n==============\nThe idea that has driven the design is that the graph-problems are quite\northogonal to the testing actions and that the problem of reporting the\nresults are orthogonal to both. The graph-problems are further decomposable\ninto path planning, stop conditions and of course loading graph files.\n\nThe added feature request to be able save and replay the path of a run\ndissolve into the path-recorder reporting class and the plain text graph\nloader.\n\nThe design is separated into these parts:\n\n* Model, (normally) supplied by the user as a graph file.\n\n* Stop condition, which bool-converts to true if its conditions are met.\n\n* Planner, which uses the model and stop condition to provide an iterable of\n plan steps as (id, name, ...) tuples.\n\n* Reporter, which is called on execution events.\n\n* Taps, installed by the reporter system to capture side-effects. (currently\n stdout/stderr and logging)\n\n* Actor supplied by the user as an object with function attributes, normally\n an object instance.\n\n* Executor that, for each step in the plan, calls the reporter and looks up\n and calls the named method on the actor. In addition to the step methods, it\n also calls a few other methods, if present on the actor.\n\n\nCode loader\n-----------\nThere is a common code-loader interface, so it's easy to load custom code and\nsupply arguments (if any, if callable) from the command line:\n\n* --foo=module.module\n\n* --foo=module.module.function\n\n* --foo=module.module.class:argument,...,keyword=value,...\n\nIf the object found is callable, it will be called, with any arguments\nsupplied, and the result used.\n\n\nFormats\n=======\n\nCurrently, Python Graphwalker understands a few simple file formats:\n\n\ngraphml\n-------\nGraphs for the original Graphwalker are typically drawn using yEd_, which\nnormally produces graphml files, so support for these have been a priority.\n\n.. _yEd: http://www.yworks.com/en/products_yed_about.html\n\n\ndot/graphviz\n------------\nPlain graphviz files can also be written, which turns out to be useful: The\nCartographer reporter uses dot to generate highlighted maps as it goes.\n\n\nplain text\n----------\n\nPlain text word lists are interpreted as a linear list of nodes to visit.\nComments of the familiar \"\\/\\* ... \\*\\/\" form are respected, as are line\ncomments of both the \"#\" and \"//\" varieties. If the first node isn't labeled\n\"Start\", such a node is added.\n\nother formats\n-------------\n\nOther formats are easy enough to add. All that you need to supply for a reader\nis an iterable of vertex (id, label) pairs and an iterable of (id, label,\nfrom-id, to-id) quadruples. Graphwalker will convert these to its internal\nformats. For write-support, you need to take a similar pair of sequences, but\nwith the difference that for the vertex and edge tuples might be longer.\n\n\nPlanners\n========\n\nThe steps to be executed by the executor are determined by one or more\nplanners. Normally, planners are expected to examine the supplied graph and\nplan a traversal of it, but the lack of enforcement creates a few special\nopportunities.\n\nPlanners are instantiated through the common code-loader interface, so it's\neasy to plug in your own planner. They're called with a graph and a StopCond\ninstance to supply an iterable containing tuples of at least two elements, as\nthe executor expects id and label.\n\nTo generate repeatable plans, use the seed keyword argument as planners keep\ntheir own random number generators.\n\n\nRandom\n------\n\nThe simplest planner, Random, traverses the graph by randomly choosing an edge\nand visiting that edge and the target vertex until the StopCond is satisfied.\nIt does not check the StopCond between edge and vertex.\n\nExample\n~~~~~~~\n ``graphwalker --stopcond=Coverage --planner=Random:seed=1337 model.dot``\n\n\nGoto\n----\nTo visit specific vertices, name them as arguments to the Goto planner. In\naddition to names and ids, 'random' will pick a vertex at random. If there is\nmore than one candidate, the one closest to the current vertex will be chosen.\n(So this does not, currently, minimize the total path.)\n\nAn integer for the keyword argument 'repeat' will repeat the name list. (but\nnot, nota bene, the specific vertices.) A repeat of zero will be taken to mean\ninfinity.\n\nExample\n~~~~~~~\n ``graphwalker --planner=Goto:happy,random,sad,repeat=10 model.dot``\n\n\nEuler\n-----\n\nTo visit all edges in the graph most efficiently, we'd like to generate an\n`Eulerian trail`_. Since the graph is not necessarily even (semi-)Eulerian,\nthe Euler planner copies the graph and modifies it. First, by cutting out the\nforced steps from the Start vertex source subgraph. The graph is then\n'eulerized' by adding edges to make it Eulerian. (in-degree equal to\nout-degree for all vertices) After the plan is created it run through the\nStopCond, to get rid of extraneous steps at the end.\n\n.. _`Eulerian trail`: http://en.wikipedia.org/wiki/Eulerian_trail\n\nExample\n~~~~~~~\n ``graphwalker --planner=Euler model.dot``\n\n\nInteractive\n-----------\nThere's often a wish to choose paths as the test is running when developing or\ndebugging models. When run, Interactive lists the edges of the current vertex\nand prompts for input. You can choose a listed edge by entering it's number,\nor you can use one of the special commands:\n\n======== ============================================\nname\n======== ============================================\ng, go to Goes to the specified vertex [1]_\nf, force Send some arbitrary name(s) as plan steps\nj, jump Set some new vertex [1]_ as the current one\nd, debug Enter the pdb debugger\nq, quit End the plan\n======== ============================================\n\n.. [1] asks if there's more than one\n\nNotes about entering the debugger\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nIf you quit from the debugger, you quit from the whole program. Catching\nBdbQuit exceptions doesn't seem to work, instead, use c/continue\n\nYou can set breakpoints in, for instance, other planners, that will\ndrop you back into the debugger after you've left it.\n\n\nStopConds - When to stop\n========================\n\nSome planners have inherent stopping conditions, others don't, so there are\nindependent conditions that can be applied to the plans. It's up to the\nplanner to consult them, to they don't always cut the test off optimally, or\nat all.\n\n\nCoverage\n--------\nThe default stop condition is coverage of 100% of edges, which means that it\nwill signal completion when it's seen all the edges in the graph. It can also\nrequire some percentage of vertices, or some percentage of each. The\npercentages are given as keywords arguments named 'edges' and 'verts' or\n'vertices'.\n\nExamples\n~~~~~~~~\n ``graphwalker --stopcond=Coverage:edges=100,verts=50 model.dot``\n\n ``graphwalker --stopcond=Coverage:vertices=25 model.dot``\n\n\nSeenSteps\n---------\nIgnoring the difference between edges and vertices, SeenSteps will simply be\ndone when it has seen all the steps it's looking for. The steps are given as\nan argument list.\n\nExamples\n~~~~~~~~\n ``graphwalker --stopcond=SeenSteps:a,e_once,b model.dot``\n\n\nCountSteps\n----------\nAgain ignoring the difference between edges and vertices, simply counts the\ntest steps and signals when some number of steps have been taken. The\nnumber of steps is the first argument, or the keyword argument 'steps',\ndefaulting to 100.\n\nExamples\n~~~~~~~~\n ``graphwalker --stopcond=CountSteps:52 model.dot``\n\n ``graphwalker --stopcond=CountSteps:steps=52 model.dot``\n\n\nActor\n=====\n\nThe test executor simply uses getattr to look up callables by the names\nsupplied by the planner, so you can implement the test code as a module, a\nclass, or, using the programmatic interface, basically any object you like.\n\nThe callables on the test object are called without arguments for now.\n\nIn addition to the labels in the graph, a few administrative methods are\nalso called, if present:\n\n* *setup* is called at the start of the test session with a dictionary\n containing the other instances involved in the test: the reporter, the\n model, and so on. Notably, if you want to save attachments from the test\n methods, you should use the reporter instance here.\n\n* *step_begin* is called before each step with the step definition. The step\n definition is an iterable where the first is the id and the second the name\n of the step.\n\n* *step_end* is called before after each step like step_begin, but with the\n addition of a failure, usually None. If the test failed, or there was some\n other exception, step_end is called with that exception, typically an\n AssertionError. The step_end method can permit the testing to continue by\n returning the exact string \"RECOVER\".\n\n* *teardown* is called the same way as setup, at the end.\n\n\nReporters\n=========\n\nTo report the results of the tests, the reporters are all called for each\nevent, notably step_begin and step_end.\n\n\nPrint\n-----\nSimply print to stdout (default) or stderr, controlled with the keyword\nargument output. If you are using the programming interface, you can send any\nfile-like, writable object. Note that combinations of Log and Print quickly\nget really confusing.\n\nExamples\n~~~~~~~~\n ``graphwalker --reporter=Print:output=stderr model.dot``\n\n\nLog\n---\nEmits to the standard python logger. The name of the logger defaults to the\nname of the reporting module, but can be set via the keyword argument\n'logger'. The level can also be set with the keyword argument 'level'. Note\nthat combinations of Log and Print quickly get really confusing.\n\nExamples\n~~~~~~~~\n ``graphwalker --reporter=Log:logger=moo,level=WARN model.dot``\n\n\nPathRecorder\n------------\nThe PathRecorder simply saves the plan step names to a text file, so that the\nrun can be replicated by feeding recording to the plain-text graph reader. The\ndirectory where the file is saved defaults to '.' but can be given as the\nkeyword argument 'path'. Likewise name defaults to the test name but can be\nset with the keyword argument 'name'. The 'attach' keyword argument, if set\n(at all) makes it try to attach it.\n\nExamples\n~~~~~~~~\n ``graphwalker --reporter=PathRecorder:path=/tmp,name=steps model.dot``\n\n ``graphwalker --reporter=PathRecorder:attach=true,name=steps model.dot``\n\n\nCartographer\n------------\nTo map the progress of the test graphically, the Cartographer reporter emits\ngraphviz files with the current step highlighted. The keyword arguments\n'dotpath' and 'imgpath' control where the graphviz input and output files go,\nrespectively, bot defaulting to '.'. The image type defaults to PNG but can be\nset using the keyword argument 'imgtype'. The 'attach' keyword argument, if\nset (at all) makes it try to attach it.\n\nExamples\n~~~~~~~~\n ``graphwalker --reporter=Cartographer model.dot``\n\n ``graphwalker --reporter=Cartographer:imgtype=jpg,attach=1 model.dot``\n\n ``graphwalker --reporter=Cartographer:dotpath=/tmp,imgpath=./www model.dot``\n\n\nTaps\n====\n\nCurrently, the there are only taps for streams and the logging system. Both\nthe logging tap and taps of standard out & error are included by default.\n\n\nFuture\n======\n\nGraphwalker itself needs a lot more, and a lot more devious tests.\n\n\nAuthors\n=======\n\nThe first iteration of the Python port of Graphwalker was written by Viktor\nHolmberg, Harald Hartwig and Chongyang Sun under the direction of Nils\n\u00d6sterling (tester) and Anders Eurenius (developer).\n\nThis iteration was rewritten from scratch by Anders Eurenius to incorporate\neverything we learned from the first.\n\n\nLicense\n=======\nThe license we have chosen is the Apache License, version 2.0. You should find\nthe full text in the file named \"LICENSE.txt\".\n\n.. LocalWords: LocalWords graphml teardown truthy AssertionError graphviz\n.. LocalWords: iterable iterables tuple tuples RNG vertices\n.. LocalWords: Goto graphwalker nota bene Eulerian subgraph FSM\n.. LocalWords: FSMs getattr verts callables stdout stderr PathRecorder pdb\n.. LocalWords: BdbQuit\n.. LocalWords: stopcond StopCond StopConds SeenSteps CountSteps\n.. LocalWords: Viktor Holmberg\n.. LocalWords: Harald Hartwig\n.. LocalWords: Chongyang Sun\n.. LocalWords: Nils \u00d6sterling\n.. LocalWords: Anders Eurenius", "description_content_type": null, "docs_url": "https://pythonhosted.org/graphwalker/", "download_url": "UNKNOWN", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "http://pypi.python.org/pypi/graphwalker/", "keywords": null, "license": "LICENSE.txt", "maintainer": null, "maintainer_email": null, "name": "graphwalker", "package_url": "https://pypi.org/project/graphwalker/", "platform": "UNKNOWN", "project_url": "https://pypi.org/project/graphwalker/", "project_urls": { "Download": "UNKNOWN", "Homepage": "http://pypi.python.org/pypi/graphwalker/" }, "release_url": "https://pypi.org/project/graphwalker/1.0.3/", "requires_dist": null, "requires_python": null, "summary": "Finite state machine based testing tool.", "version": "1.0.3" }, "last_serial": 1464169, "releases": { "1.0.2": [ { "comment_text": "", "digests": { "md5": "9687f6e232372c597f681e1f2fae18bd", "sha256": "2b6e591a778ea93527a17b84243de0ea29c717265b4831a24a67fb17750c58ee" }, "downloads": -1, "filename": "graphwalker-1.0.2.tar.gz", "has_sig": false, "md5_digest": "9687f6e232372c597f681e1f2fae18bd", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 42236, "upload_time": "2013-03-19T20:20:25", "url": "https://files.pythonhosted.org/packages/06/d6/5e3ea2077c878ff4eaa98f3cea53def2cd4076819fab6f4a6633b42575f2/graphwalker-1.0.2.tar.gz" } ], "1.0.3": [ { "comment_text": "", "digests": { "md5": "e08955af806baaae2394364d6cbafe07", "sha256": "2ec5768b56d7ef9727a46527c302ce1b6766da84f9931b3ae4850a48c75859ad" }, "downloads": -1, "filename": "graphwalker-1.0.3.tar.gz", "has_sig": false, "md5_digest": "e08955af806baaae2394364d6cbafe07", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 69989, "upload_time": "2015-03-17T11:22:15", "url": "https://files.pythonhosted.org/packages/38/07/f08941fda15e53630c8bc472c07825232c036011c1c02b5b8b84ef8c9a34/graphwalker-1.0.3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "e08955af806baaae2394364d6cbafe07", "sha256": "2ec5768b56d7ef9727a46527c302ce1b6766da84f9931b3ae4850a48c75859ad" }, "downloads": -1, "filename": "graphwalker-1.0.3.tar.gz", "has_sig": false, "md5_digest": "e08955af806baaae2394364d6cbafe07", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 69989, "upload_time": "2015-03-17T11:22:15", "url": "https://files.pythonhosted.org/packages/38/07/f08941fda15e53630c8bc472c07825232c036011c1c02b5b8b84ef8c9a34/graphwalker-1.0.3.tar.gz" } ] }