<html>
  <head>
    <meta content="text/html; charset=ISO-8859-1"
      http-equiv="Content-Type">
  </head>
  <body bgcolor="#FFFFFF" text="#000000">
    <div class="moz-cite-prefix"><br>
      On 01/15/2014 08:35 PM, Ryan Smith-Roberts wrote:<br>
    </div>
    <blockquote
cite="mid:CABPWfCHuK7CG5Cj6cOTqbAMK=LKJUF7vMVA53CL12v2RgR+Jgw@mail.gmail.com"
      type="cite">
      <div dir="ltr">
        <div class="gmail_extra">
          <div class="gmail_quote">On Wed, Jan 15, 2014 at 7:57 PM, Ryan
            Smith-Roberts <span dir="ltr"><<a moz-do-not-send="true"
                href="mailto:rmsr@lab.net" target="_blank">rmsr@lab.net</a>></span>
            wrote:<br>
            <blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
              <div dir="ltr">
                <div>socket.getservbyname(servicename[, protocolname])</div>
                <div>-></div>
                <div>socket.getservbyname(servicename,
                  protocolname=None)</div>
              </div>
            </blockquote>
            <div><br>
            </div>
            <div>Here is a more complicated example, since the above
              does technically have an alternative fix:</div>
            <div>
              <br>
            </div>
            <div>sockobj.sendmsg(buffers[, ancdata[, flags[, address]]])</div>
            <div>-></div>
            <div>sockobj.sendmsg(buffers, ancdata=None, flags=0,
              address=None)<br>
            </div>
          </div>
        </div>
      </div>
    </blockquote>
    <br>
    I feel like Ryan didn't sufficiently explain the problem.  I'll
    elaborate.<br>
    <br>
    <br>
    For functions implemented in Python, it's always true that:<br>
    <ul>
      <li>a parameter that is optional always has a default value, and</li>
      <li>this default value is visible to Python and is a Python value.</li>
    </ul>
    The default value of every parameter is part of the function's
    signature--you can see them with inspect.signature() or
    inspect.getfullargspec().<br>
    <br>
    A corollary of this: for every function implemented in Python, you
    can construct a call to it where you fill in every optional value
    with its published default value, and this is exactly equivalent to
    calling it without specifying those arguments:<br>
    <blockquote>def foo(a=any_python_value): ...<br>
      <br>
      sig = inspect.signature(foo)<br>
      defaults = [p.default for p in sig.parameters.values()]<br>
      foo(*defaults) == foo()<br>
    </blockquote>
    Assuming neither foo nor "any_python_value" have side effects, those
    two calls to foo() will be exactly the same in every way.<br>
    <br>
    <br>
    But!  Builtin functions implemented in C commonly have optional
    parameters whose default value is not only opaque to Python, it's
    not renderable as a Python value.  That default value is NULL. 
    Consider the first two paragraphs of SHA1_new() in
    Modules/sha1module.c:<br>
    <blockquote>static PyObject *<br>
      SHA1_new(PyObject *self, PyObject *args, PyObject *kwdict)<br>
      {<br>
          static char *kwlist[] = {"string", NULL};<br>
          SHA1object *new;<br>
          PyObject *data_obj = NULL;<br>
          Py_buffer buf;<br>
      <br>
          if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|O:new",
      kwlist,<br>
                                           &data_obj)) {<br>
              return NULL;<br>
          }<br>
      ...<br>
    </blockquote>
    The "string" parameter is optional.  Its value, if specified, is
    written to "data_obj".  "data_obj" has a default value of NULL. 
    There is no Python value you could pass in to this function that
    would result in "data_obj" being (redundantly) set to NULL.  In
    Python SHA1_new is known as "_sha1.sha1".  And:<br>
    <blockquote>sig = inspect.signature(_sha1.sha1)<br>
      defaults = [p.default for p in sig.parameters.values()]<br>
      _sha1.sha1(*defaults) == _sha1.sha1()<br>
    </blockquote>
    There's no value we could put in the signature for _sha1.sha1 that
    would behave exactly the same as that NULL.<br>
    <br>
    The ultimate goal of Argument Clinic is to provide introspection
    information for builtins.  But we can't provide a default value to
    Python for the "string" parameter to _sha1.sha1() without changing
    the semantics of the function.  We're stuck.<br>
    <br>
    Ryan's question, then, is "can we change a function like this so it
    accepts None?"  My initial reaction is "no".  That might be okay for
    _sha1.sha1(), but it'd be best to avoid.<br>
    <br>
    In the specific case of SHA1_new's "string" parameter, we could lie
    and claim that the default value is b''.  Internally we could still
    use NULL as a default and get away with it.  But this is only a
    happy coincidence.  Many (most?) functions like this won't have a
    clever
    Python value we can trick you with.<br>
    <br>
    What else could we do?  We could add a special value, let's call it
    sys.NULL, whose specific semantics are "turns into NULL when passed
    into builtins".  This would solve the problem but it's really,
    really awful.<br>
    <br>
    The only other option I can see: don't convert SHA1_new() to use
    Argument Clinic, and don't provide introspection information for it
    either.<br>
    <br>
    Can you, gentle reader, suggest a better option?<br>
    <br>
    <br>
    <i>/arry</i><br>
    <br>
    p.s. Ryan's function signatures above suggest that he's converting
    code from using PyArg_ParseTuple into using
    PyArg_ParseTupleAndKeywords.  I don't think he's *actually* doing
    that, and if I saw that in patches submitted to me I would ask that
    it be fixed.<br>
  </body>
</html>