<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>