Package: grappa
Aboutgrappais a behavior-oriented, self-declarative, expressive and developer-friendly
lightweight assertion library forPythonthat aims to make testing more productive and frictionless for humans.grappacomes with two declarativeassertion styles:expectandshould.It also comes with a detailed, human-friendlyerror reportingsystem that aims to reduce friction,
provide better feedback and improve human speed and agility while identifying and fixing errors.To get started, take a look to theshowcasecode,tutorial, availablepluginsandoperators documentation.For HTTP protocol assertions, seegrappa-http.Statusgrappais consideredstablesoftware, however it’s not mature, widely used software.
New features may be added from time to time or minor bugs may be experienced.Community contributions and bug reports are very welcome.ShowcaseA small example demonstrating somegrappafeatures.
Seedocumentationandtutorialfor more examples.fromgrappaimportshouldTrue|should.be.trueFalse|should.be.falseNone|should.be.none''|should.be.empty[]|should.be.empty'foo'|should.exists3.14|should.be.lower.than(4)3.14|should.be.higher.than(3)3.14|should.be.within(2,4)'bar'|should.be.equal.to('bar',msg='value is not "bar"')[1,2,3]|should.be.equal.to([1,2,3])'hello, grappa'|should.startswith('hello')'hello, grappa'|should.endswith('grappa')[1,2,3,4]|should.startswith(1)[1,2,3,4]|should.endswith(4)'Hello grappa'|should.match('(\W)+ grappa$')'Hello grappa'|should.contain('grappa')|should.contain('he')['foo','bar']|should.contain('foo')|should.do_not.contain('baz')'foo'|should.be.a('string'){'foo':True}|should.be.a('dict')iter([1,2,3])|should.have.length.of(3)[1,2,3]|should.be.a('list')>should.have.length.of(3)(lambdax:x)|should.be.callable(lambdax:x)|should.not_have.type.of('generator')'foo'|should.pass_test(lambdax:xin'foo bar')'foo'|should.pass_function(lambdax:len(x)>2)(lambda:x)|should.raises(NameError)(lambda:x)|should.does_not.raises(RuntimeError){'foo':'bar'}|should.have.key('foo').that.should.be.equal('bar')(1,2,3,4)|should.be.a(tuple)>should.have.index.at(3)>should.be.equal.to(4)an_object|should.have.properties('foo','bar','baz')an_object|should.implement.methods('foo','bar','baz'){'foo':True,'bar':False}|should.all(should.have.key('foo'),should.have.key('bar')){'foo':True,'bar':False}|should.any(should.have.key('foo'),should.have.key('baz'))({'bar':[1,2,3]}|should.have.key('bar')>should.be.a('list')>should.have.length.of(3)>should.contain.item(3)>should.have.index.at(1)>should.be.equal.to(2))withshould('foo'):should.be.a(str)should.have.length.of(3)should.be.equal.to('foo')Let’s see how the error report looks like ingrapparunning inpytest.Seeerror reportingdocumentation for more details about howgrappaerror report system works.======================================================================FAIL:tests.should_test.test_grappa_assert======================================================================Traceback(mostrecentcalllast):File".pyenv/versions/3.6.0/lib/python3.6/site-packages/nose/case.py",line198,inrunTestself.test(*self.arg)File"grappa/tests/should_test.py",line16,intest_grappa_assertx|should.be.have.length.of(4)File"grappa/grappa/test.py",line248,in__ror__returnself.__overload__(value)File"grappa/grappa/test.py",line236,in__overload__returnself.__call__(subject,overload=True)File"grappa/grappa/test.py",line108,in__call__returnself._trigger()ifoverloadelseTest(subject)File"grappa/grappa/test.py",line153,in_triggerraiseerrAssertionError:Oops!Somethingwentwrong!Thefollowingassertionwasnotsatisfiedsubject"[1, 2, 3]"shouldbehavelengthof"4"Messagesubjectlistmusthaveatleast4itemsReasons▸unexpectedobjectlength:3Whatweexpectedanobjectthatcanbelengthmeasuredanditslengthisequalto4Whatwegotinsteadanobjectoftype"list"withlength3Information▸Objectlengthismeasuredbyusing"len()"built-inPythonfunctionorconsuminganlazyiterable,suchasagenerator.Mostbuilt-intypesandobjectsinPythoncanbetestedthatway,suchasstr,list,tuple,dict...aswellasanyobjectthatimplements"__len__()"method.—Reference:https://docs.python.org/3/library/functions.html#lenWhereFile"grappa/tests/should_test.py",line16,intest_grappa_assert8|9|deftest_native_assert():10|x=[1,2,3]11|assertlen(x)==412|13|14|deftest_grappa_assert():15|x=[1,2,3]16|>x|should.be.have.length.of(4)17|18|19|deftest_bool():20|True|should.be.true|should.be.present21|False|should.be.false|should.be.equal.to(False)22|False|should.be.false|should.not_be.equal.to(True)DemoWhy grappa?grappaaims to assist humans while doing a very recurrent and not very fun task in software development: testing things.The core idea behindgrappacomes from the fact that human time is considerably more expensive than machine time,
and therefore any machine assistance to optimize processes and close the gap is beneficial.Withgrappayou can express almost in plain English what the test contract actually is, but in a way that’s
fun and easy to write but also more easy and pleasant to read or maintain by other developers.The Zen of grappaTesting is about feedback: detailed, easy to understand, human-friendly is always better.Frictionless testing: introducing self-declarative behavior testing patterns can make testing more fun for test writers and more enjoyable for test readers.Expressivity is paramount: humans should easily understand what the code is doing.Human time is expensive: any modern software should assist people to identify and understand errors easily.Make error reporting great again: feedback during testing is key, let’s make it more handy and less frustrating.Testing patterns consolidation: software expectations are limited to the boundaries of language data types and structures.Hurt less feelings: seeing errors is not a nice thing, but it can be painless if details are showed you in a more gentle way.FeaturesBehavior-oriented expressive fluent API.Built-in assertion DSL with English lexicon and semantics.Supports bothexpectandshouldassertion styles.Full-featured built-inassertion operators.Human-friendly and detailederror reporting.Built-in expectations difference comparison between subject and expected values.Extensible assertions supporting third-partyplugins.Assertion chaining and composition.Composable assertion via logical operators such asand&or.Testing framework agnostic. Works withunittest,nosetests,pytest,behave…Easy to hack via programmatic API.Lightweight and (almost) dependency-free.Works with Python 2.7+, 3+, PyPy and potentially with other Python implementations.InstallationUsingpippackage manager:pipinstall--upgradegrappaOr install the latest sources from Github:pipinstall-egit+git://github.com/grappa-py/grappa.git#egg=grappaHistory1.0.1 / 2020-11-21Merge pull request #65 from sgissinger/master2.7 correction (maybe)fixes #54 add message redirection to exceptions1.0.0 / 2020-11-21feat: major version v1fix: #53, #55, #48, #59 (credits to sgissinger)feat: added mock call operators (credits to sgissinger)make github actions fail on every flake8pass flake8enforce implements operatormissing kwargs argumentadd contain testsnormalize code between contain and key and add lists expectations to containimprove been_called_with reasons when falseuse os.path.join instead of remove and Foo class for spy testsos.path.basename not a good candidate to count mock calls because it seems to call itselfmissing experimental for pypy2re-try to use pypy2 on github actionsskip tests which does not work on pypy2add contain testscontain now supports dicts and arrays. Partially fix #59use isinstanceimprove keys operator tests and add array testskeys operator now supports arraysset env var in step onlyallow errors on 3.10-dev buildsallow insecure commands for github action nightlyupgrade action versionrun 3.10-dev on ubuntu onlyadd python 3.10 nightly to github action pipelineset 50 chars to normalization sizeflake8 correction and docstrings upgradeadd key operator testskey operator simplified and works with tuples, lists and sets. fixes #48 ?do not upgrade pip on github actionstry to use pypy only on ubuntu for github actionsuse only include for pypyadd python 3.9, prefer jobs over matrix, add pypy env var in travis ciadd mocker stop alladd python 3.9 to github actionspypy2 does not seem to work in github actions like it does in TravisCIexclude pypy2 on ubuntuexclude macos pypy2 from ci matrixuse pypy2 insteadadd pypy to github actionsCreate python-package.ymladded mock impl validator docstring and error tipsadded explicit docstrings to have_been operatorsuse pytest-mock 2.0.0 for python 2.7make flake8 passset exception __cause__ to get direct causes when internal exceptions occursmove mock implementation to decorators moduleadd tests using pytest-mock spies and stubs which are basic funcsdo not rely explicitly on MagicMock but test needed implementationbetter get attribute handlingbetter called once messagesadd been_called operator testsadd been_called operatorsmissing end linefixes #55 should.not_have.key(…)once negated a sentence stays negatedmake accessor be calledfix(Makefile): lovely tabsfix(Makefile): use twine for publishing0.1.12 / 2020-02-26feat(version): bimpfeat(setup): add python 3.7 & 3.8 classifiersMerge pull request #56 from jdlourenco/collections-abc-sixupdate code according flake8 warnings and errorsfeat(requirements): bump flake8feat(travis): add python 3.7 & 3.8fix(travis): remove python 3.3 & 3.4change bump six to 0.14change use six.moves.collections_abc module for importing classes that moved to the collections.abc module on python30.1.10 / 2018-10-02feat: addonlyoperator #450.1.9 / 2018-06-02fix(#42): Add string comparison parity for Python 2.7v0.1.8 / 2018-01-23Merge pull request #39 from dancingcactus/masterRemoves unused importsAllow partials to be used with raises operatorsfix(operator): minor type in exception messageMerge pull request #38 from dancingcactus/masterUpdates the docs for Raises to encapsulate feedback from #37Update README.rstrefactor(docs): remove codesponsorfeat(docs): add sponsor adfeat(docs): update status notefeat(docs): update status noteMerge branch ‘master’ ofhttps://github.com/grappa-py/grappafix(docs): use proper organization nameUpdate AUTHORSrefactor(docs): import AUTHORS filefeat: add AUTHORS filefix(setup.py): update package URLv0.1.7 / 2017-05-12feat(#33): show available operators on attribute errorfeat(#36): add allowed assertion attributes on errorv0.1.6 / 2017-04-28fix(type): expose proper type value if a type value is the expected valuefix(reporter): use search() instead of match() for line code matching. fix(reporters): escape underscore sequencesv0.1.5 / 2017-04-28feat(reporters): add code reporterfeat(operators): add “that_is”, “which_is” attribute DSL operatorsrefactor(reporter): match additional negation assertionsv0.1.4 / 2017-04-27feat(reporters): match attribute expressions for proper code line reportingfeat(equal): enable show_diff report in operatorfix(index_test): bad file formattingrefactor(index_test): add error test caserefactor(index_test): remove commented codefeat(docs): add context assertion example in tutorialfeat(docs): add context manager examplefix(docs): update error exception examplerefactor(docs): update showcase examplefeat(operators): add not_satisfy attribute operatorv0.1.3 / 2017-03-29feat(docs): add raise exception examplesrefactor(docs): update showcase examplefeat(reporter): normalize value output in subject/expect sectionsfeat(docs): update examples and FAQs. feat(operators): add aliases for start/end operatorfeat(docs): add link to grappa-http pluginrefactor(docs): add operators type sectionrefactor(docs): add beta status documentation noticefeat(docs): update descriptionrefactor(docs): update status descriptionfeat(docs): update linksv0.1.2 / 2017-03-26feat(docs): add matchers supported keyword argumentsfeat(docs): improve descriptionsfeat(operators): improve length operator for access based chainingfix(docs): update error custom message examplefeat(docs): improve documentation. adds operators composition sectionfix(setup.py): add author emailv0.1.1 / 2017-03-23refactor(diff): process expected values as tuple firstfix(contain): remove print statementsrefactor(core): normalize yielding syntax, add missing documentationrefactor(core): normalize yielding syntax, add missing documentationfeat(#26): support disable operator chainingfeat(#28): better assertion reporting. feat(operators): add index operatorrefactor(reporter): support raw mode with proper indent pretty printingrefactor(operators): add satisfy/satisfies attribute operatorsfeat(diff): consume diff specific subject/expected valuesfeat(operators): add is/is_not operator attributesrefactor(core): isolate reporters per modulefeat(#13, #25): add suboperators support and diff output reportrefactor(docs): update organization namerefactor(docs): update project imagerefactor(reporter): ignore subject/expected output if emptyrefactor(reporter): show diff if enabledfeat(docs): add in a nutshell sectionfeat(#24, #25): feature enhancementsfeat(docs): add say thanks badgerefactor(reporter): load value from operator firstfix(docs): use proper badgesfix(docs): update type operator examplesfix(metadata): updaterefactor(test): add chained test for keysfeat(Makefile): add publish commands0.1.0 (2017-03-05)First version (beta)