<div dir="ltr"><div class="gmail_quote"><div dir="ltr"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">It’s obvious but there is one easy way to shorten the code: using **kwargs. It’s way shorter but the down sides are: </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">- the “real” function signature gets hidden so IDEs for example won’t pick it up<br>- the error when you make a mistake when calling is not in your code anymore but one level down. </blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">This is confusing. One could imagine solving this specific case by having a type annotation of “this function has the types of that function”. Maybe: def _open(*args: args_of_(sync_open), **kwargs: kwargs_of(sync_open) -> return_of(sync_open): But of course this only solves the case where there is a 1:1 mapping. / Anders</blockquote><div>These problems could be solved by a decorator that accepts string representation of the signature. The decorator would then have to parse the signature at importing time and set it to the __signature__ attribute on the resultant function. This decorator would also need to bind the arguments e.g. sig.bind(*args, **<span class="m_5890566569189907004gmail-gr_ m_5890566569189907004gmail-gr_487 m_5890566569189907004gmail-gr-alert m_5890566569189907004gmail-gr_spell m_5890566569189907004gmail-gr_inline_cards m_5890566569189907004gmail-gr_disable_anim_appear m_5890566569189907004gmail-ContextualSpelling" id="m_5890566569189907004gmail-487" style="display:inline;border-bottom:2px solid transparent;background-repeat:no-repeat;color:inherit;font-size:inherit">kwargs</span>), to handle out of order positional arguments. Therefore this would raise an error in the decorator, essentially solving your second point. </div><div><br></div><div>This would make the example look like this, a lot clearer in my opionion:</div><div><br></div>@signature('''(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None,<br>                       closefd=True, opener=None, *, loop=None, executor=None)''')<br>def open(*args, **kwargs):<br>      return AiofilesContextManager(_open(*args, **kwargs))<br><br>@asyncio.coroutine<br>def _open(*args, loop=None, executor=None, **kwargs):<br>     """Open an asyncio file."""<br>     if loop is None:<br>         loop = asyncio.get_event_loop()<br>     cb = partial(sync_open, *args, **kwargs)<br>     f = yield from loop.run_in_executor(executor, cb)<br><br>     return wrap(f, loop=loop, executor=executor)<div><br></div><div>Ben Lewis</div></div>
</div></div>