proofit404 / stories Goto Github PK
View Code? Open in Web Editor NEWService objects designed with OOP in mind.
Home Page: https://proofit404.github.io/stories/
License: BSD 2-Clause "Simplified" License
Service objects designed with OOP in mind.
Home Page: https://proofit404.github.io/stories/
License: BSD 2-Clause "Simplified" License
Declarative context values validation.
Applies gradually as context fills in.
from stories import story, arguments
class Action:
@story
@arguments("foo")
def do(I):
pass
Action.do.contract({
"foo": lambda value: (None, 'integer required')
})
>>> Action().do(foo='5')
ContextContractError: foo variable is invalid (integer required)
While story executed we submit events to some event store.
We can look at some system UI and say: "this step will fail only in 12%"
We can show hit-map by storylines.
Context variables shown in the class like view with story points by which they were set in the order of execution.
>>> print(self.ctx)
Context:
foo = 1 # Set by Simple.one
bar = 2 # Set by Simple.two
Show Exception class name in the last statement.
from dependencies import Injector
from dependencies.contrib.rest_framework import model_view_set
from stories import story, argument
class CreateStory:
@story
@argument("user")
@argument("text")
def create(self):
self.persist_poll()
self.create_review()
@model_view_set
class Polls(Injector):
# Take story arguments from the injector.
# Take failure handlers (on method & for reason) from the injector.
# Result value will be passed to the rest framework as usual.
#
# How to avoid rest framework in the failure handlers?
create = CreatePoll.create.bind()
update = ChangePoll.change.bind()
text = serializer.data["text"] # Story argument.
def on_create_review_failure():
return Response ({"detail": "Bad review", "error_code": 123})
Instead of this:
User.objects.create(name=self.ctx.name, email=self.ctx.email, age=self.ctx.age)
How about this:
User.objects.create(**self.ctx('name', 'email', 'age'))
In case of different keyword arguments
User.objects.create(**self.ctx(username='name'))
Maybe context and failure annotations.
For example, we are running story in the Celery task.
But this task was delayed from somewhere.
It may be a different story with its own execution path and context.
Showing this path and context in the called task can be really helpful to debug problems.
Should be supported by #38
This is leading into the concept of Delegate
s. Canvas
is an example of the Delegate
.
Generally speaking, we are trying to solve this problem:
result = story1()
story2(result) # fails without knowing anything about story1 context.
If this code was written in this below, it will be way more easy to debug.
d = Delegate(story2)
story1(d)
d() # Takes arguments from story1 context.
GraphQL mutations are perfect candidates for delegates.
They are executed sequentially one after another.
If mutation number 10 fails, we would like to see the execution path of the previous 9.
As always, composition is a superior pattern & I'm glad that this feature was designed around it.
Delegates could be used to execute nested stories in parallel or concurrently.
Specific delegates implementation like stories-asyncio
or stories-celery
could run delegates any way they like.
The best part of that decision, all implementation specific details will be moved to the composition (Injector) step.
For example, stories-asyncio
could execute nested stories using gather function. Outer story will be continue it's execution after it was suspended to execute delegate.
In comparison, stories-celery
could execute nested stories using group part of chore canvas. Outer story will be head part of the same chore and will be scheduled as a separate task and will restore its state the same way nested stories did.
State object store not only normalized values, but also it store initial data for each value. Usually, it is entity and a dictionary of its arguments.
In that case, stories-celery
would serialize initial data as task argument.
Before delegate continue it's execution on another machine, contract will apply normalization and restore entity classes the same way it did in the first story.
That way we would use instances of our classes traveling over network without pickle.
Submit proxy and context representation to the breadcrumbs the same way we do with py.test plugin.
CSS and HTML should look like in the 500 page with DEBUG = True.
pdb
up
& ctx
usage example in the debugging chapter.StoryError
instead of failed assertvalidate_substory_arguments
message, given context, and required arguments.from stories import story, parallel
class Order:
@story
def purchase(I):
I.one
with parallel:
I.two
I.three
I.four
parallel
should have at least two steps in it.two
should not be visible to the three
and wise versa. Context changes made by two
and three
should be visible by four
.two
, three
or both of them could be a substory. Context restrictions continue to be the same independent from this detail.Result
this will be a result of the whole story. If other parallel steps are still running, their result should be ignored when they return. The story returns only after all the steps complete. If other running steps returns Failure
or Result
a warning of this clash should be reported.Failure
this will be a failure of the whole story. If other parallel steps are still running, their result should be ignored when they return. The story fails only after all the steps complete. If other running steps returns Failure
or Result
a warning of this clash should be reported.<parallel>
should be present in the representation of the story.class Simple:
@story
def x(self):
self.one()
self.two()
self.three()
def one(self):
return Success()
def two(self):
print(self)
return Success()
def three(self):
return Result()
>>> Simple().x()
Simple.x
one
>> two
three
>>>
Without any print
statements in your tests.
Failure
result classBefore call check, if given class has only stories and methods used by stories.
Use should be able to:
transaction.atomic
around substory even if there were Skip
, Result
or even Failure
.Skip
was returned. Probably Rollback(to=Skip())
will do the trick.A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.