Chris Angelico writes:

 > Okay, but what is the contract that's being violated when you use
 > data= ? How would you define the contract that this would track?
 > That's what I'm asking.

The output is input to some other component.  In production, that
component would not be under your control, perhaps, but in testing it
surely is.  The contract would be associated with the other component,
and it would be "my input is JSON".

Alternatively, if "your" component is being used in a protocol that
specifies JSON, the contract could be "what I post is JSON".  Presumably
that contract can't be checked in production, but in testing it could
be.  If the inputs to your component satisfy their contracts, but JSON
isn't coming out, the problem is in your component.

Ie, I don't see how DbC can diagnose *how* a component is broken, in
general.  It *can* localize the breakage, and provide some hints based
on the particular contract that is "violated".

I think this shows that in a broad class of cases, for existing code,
DbC doesn't do much that a developer with a debugger (such as print()
;-) can't already do, and the developer can do it much more flexibly.

However, getting meta,

 > Just had a confused developer wondering why calling an API with
 > session.post(...., data={...some object dict here}) didn't work
 > properly. (Solved by s/data/json)

session.post seems to be a pretty horrible API.  You'd think this
would either be

    session.post_json(..., data={...})

or

    session.post(..., data={...}, format='json')

with the former preferred (and session.post deprecated in favor of
session.form_encoded; I guess you could also use the latter and
require the 'format' argument).

How would this help in the DbC context?  Your server (if you own it),
or your mock server in the test suite, will complain that its contract
"my input is JSON" is being violated, because it's explicitly an entry
condition, your programmer looks at the component that's supposed to
produce JSON, sees "form_encoded" either in the function name or the
format argument's value, and the likelihood of confusion is small.

The contribution of DbC here is not in the contract itself, but in the
discipline of thinking "how would I write this contract so that its
violation would point me to the coding error?", which leads to
refactoring the 'post' method.

Is DbC better than the server doing "assert is_valid_json(input)"?
That too works best with the suggested refactoring.  Evidently it's
not better, but there are things that assert can't do.  For
example, the server might incrementally parse the JSON, yielding
useful subobjects as you go along.  Then you can't just assert
is_valid_json at the beginning of the response generator; you need to
do this at the server level.  A DbC toolkit would presumably provide a
way to decorate the server with

    try:
        server.accept_json_object()
    except JSONParseError as e:
        report_contract_violation(e)

This is, of course, all imaginary, and I have no idea whether it would
work as suggested in practice.  It will be interesting to me to see,
not only Marko's contracts in a DbC-ized module, but also places where
he demands refactoring so that an *informative* contract can be
written.

Steve

_______________________________________________
Python-ideas mailing list
Python-ideas@python.org
https://mail.python.org/mailman/listinfo/python-ideas
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to