<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:w="urn:schemas-microsoft-com:office:word" xmlns:m="http://schemas.microsoft.com/office/2004/12/omml" xmlns="http://www.w3.org/TR/REC-html40">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="Generator" content="Microsoft Word 15 (filtered medium)">
<!--[if !mso]><style>v\:* {behavior:url(#default#VML);}
o\:* {behavior:url(#default#VML);}
w\:* {behavior:url(#default#VML);}
.shape {behavior:url(#default#VML);}
</style><![endif]--><style><!--
/* Font Definitions */
@font-face
        {font-family:Wingdings;
        panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
        {font-family:"Cambria Math";
        panose-1:2 4 5 3 5 4 6 3 2 4;}
@font-face
        {font-family:Calibri;
        panose-1:2 15 5 2 2 2 4 3 2 4;}
@font-face
        {font-family:Georgia;
        panose-1:2 4 5 2 5 4 5 2 3 3;}
/* Style Definitions */
p.MsoNormal, li.MsoNormal, div.MsoNormal
        {margin:0cm;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
h2
        {mso-style-priority:9;
        mso-style-link:"Titre 2 Car";
        mso-margin-top-alt:auto;
        margin-right:0cm;
        mso-margin-bottom-alt:auto;
        margin-left:0cm;
        font-size:18.0pt;
        font-family:"Calibri",sans-serif;
        font-weight:bold;}
a:link, span.MsoHyperlink
        {mso-style-priority:99;
        color:blue;
        text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
        {mso-style-priority:99;
        color:purple;
        text-decoration:underline;}
pre
        {mso-style-priority:99;
        mso-style-link:"Préformaté HTML Car";
        margin:0cm;
        margin-bottom:.0001pt;
        font-size:10.0pt;
        font-family:"Courier New";}
p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph
        {mso-style-priority:34;
        margin-top:0cm;
        margin-right:0cm;
        margin-bottom:0cm;
        margin-left:36.0pt;
        margin-bottom:.0001pt;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
span.Titre2Car
        {mso-style-name:"Titre 2 Car";
        mso-style-priority:9;
        mso-style-link:"Titre 2";
        font-family:"Calibri Light",sans-serif;
        color:#2F5496;}
p.msonormal0, li.msonormal0, div.msonormal0
        {mso-style-name:msonormal;
        mso-margin-top-alt:auto;
        margin-right:0cm;
        mso-margin-bottom-alt:auto;
        margin-left:0cm;
        font-size:11.0pt;
        font-family:"Calibri",sans-serif;}
span.EmailStyle20
        {mso-style-type:personal;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
span.PrformatHTMLCar
        {mso-style-name:"Préformaté HTML Car";
        mso-style-priority:99;
        mso-style-link:"Préformaté HTML";
        font-family:"Courier New";}
span.k
        {mso-style-name:k;}
span.nf
        {mso-style-name:nf;}
span.p
        {mso-style-name:p;}
span.n
        {mso-style-name:n;}
span.o
        {mso-style-name:o;}
span.kc
        {mso-style-name:kc;}
span.mi
        {mso-style-name:mi;}
span.ow
        {mso-style-name:ow;}
span.nd
        {mso-style-name:nd;}
span.EmailStyle33
        {mso-style-type:personal-compose;
        font-family:"Calibri",sans-serif;
        color:windowtext;}
.MsoChpDefault
        {mso-style-type:export-only;
        font-size:10.0pt;}
@page WordSection1
        {size:612.0pt 792.0pt;
        margin:70.85pt 70.85pt 70.85pt 70.85pt;}
div.WordSection1
        {page:WordSection1;}
/* List Definitions */
@list l0
        {mso-list-id:57872163;
        mso-list-type:hybrid;
        mso-list-template-ids:1854304182 -1235601456 67895299 67895301 67895297 67895299 67895301 67895297 67895299 67895301;}
@list l0:level1
        {mso-level-start-at:0;
        mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;
        mso-fareast-font-family:Calibri;
        mso-bidi-font-family:"Times New Roman";}
@list l0:level2
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l0:level3
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l0:level4
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Symbol;}
@list l0:level5
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l0:level6
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l0:level7
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Symbol;}
@list l0:level8
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l0:level9
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l1
        {mso-list-id:261571156;
        mso-list-type:hybrid;
        mso-list-template-ids:2092063066 -1729353350 67895299 67895301 67895297 67895299 67895301 67895297 67895299 67895301;}
@list l1:level1
        {mso-level-start-at:0;
        mso-level-number-format:bullet;
        mso-level-text:-;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Calibri",sans-serif;
        mso-fareast-font-family:Calibri;}
@list l1:level2
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l1:level3
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l1:level4
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Symbol;}
@list l1:level5
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l1:level6
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l1:level7
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Symbol;}
@list l1:level8
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l1:level9
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l2
        {mso-list-id:897477263;
        mso-list-type:hybrid;
        mso-list-template-ids:-544281056 -1550580536 67895299 67895301 67895297 67895299 67895301 67895297 67895299 67895301;}
@list l2:level1
        {mso-level-start-at:0;
        mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;
        mso-fareast-font-family:Calibri;
        mso-bidi-font-family:"Times New Roman";}
@list l2:level2
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l2:level3
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l2:level4
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Symbol;}
@list l2:level5
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l2:level6
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l2:level7
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Symbol;}
@list l2:level8
        {mso-level-number-format:bullet;
        mso-level-text:o;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:"Courier New";}
@list l2:level9
        {mso-level-number-format:bullet;
        mso-level-text:;
        mso-level-tab-stop:none;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        font-family:Wingdings;}
@list l3
        {mso-list-id:941842172;
        mso-list-template-ids:1608163590;}
@list l3:level1
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:36.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
@list l3:level2
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:72.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
@list l3:level3
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:108.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
@list l3:level4
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:144.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
@list l3:level5
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:180.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
@list l3:level6
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:216.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
@list l3:level7
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:252.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
@list l3:level8
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:288.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
@list l3:level9
        {mso-level-number-format:bullet;
        mso-level-text:ï‚·;
        mso-level-tab-stop:324.0pt;
        mso-level-number-position:left;
        text-indent:-18.0pt;
        mso-ansi-font-size:10.0pt;
        font-family:Symbol;}
ol
        {margin-bottom:0cm;}
ul
        {margin-bottom:0cm;}
--></style><!--[if gte mso 9]><xml>
<o:shapedefaults v:ext="edit" spidmax="1026" />
</xml><![endif]--><!--[if gte mso 9]><xml>
<o:shapelayout v:ext="edit">
<o:idmap v:ext="edit" data="1" />
</o:shapelayout></xml><![endif]-->
</head>
<body lang="FR" link="blue" vlink="purple">
<div class="WordSection1">
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Thanks David,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US">> I did write the book _Functional Programming in Python_, so I'm not entirely unfamiliar with function wrappers.</span><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Nice ! I did not realize ; good job here, congrats! ;)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">--<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">I carefully read the documentation you pointed at,
<a href="https://wrapt.readthedocs.io/en/latest/decorators.html#decorators-with-optional-arguments">
https://wrapt.readthedocs.io/en/latest/decorators.html#decorators-with-optional-arguments</a>
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">This is the example shown by the author:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">def with_optional_arguments(wrapped=None, myarg1=1, myarg2=2):<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">    if wrapped is None:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">        return functools.partial(with_optional_arguments,<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">                myarg1=myarg1, myarg2=myarg2)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">    @wrapt.decorator<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">    def wrapper(wrapped, instance, args, kwargs):<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">        return wrapped(*args, **kwargs)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New""><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">    return wrapper(wrapped)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">As you can see:<o:p></o:p></span></p>
<ul style="margin-top:0cm" type="disc">
<li class="MsoListParagraph" style="margin-left:0cm;mso-list:l1 level1 lfo3"><span lang="EN-US" style="mso-fareast-language:EN-US">the developer has to explicitly handle the no-parenthesis case (the first two lines of code).<o:p></o:p></span></li><li class="MsoListParagraph" style="margin-left:0cm;mso-list:l1 level1 lfo3"><span lang="EN-US" style="mso-fareast-language:EN-US">And in the next lines of the doc you see his recommendations â€œ</span><span lang="EN-US">For this to be used in this way, it is
 a requirement that the decorator arguments be supplied as keyword arguments. If using Python 3, the requirement to use keyword only arguments can again be enforced using the keyword only argument syntax.”
</span><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p></o:p></span></li><li class="MsoListParagraph" style="margin-left:0cm;mso-list:l1 level1 lfo3"><span lang="EN-US" style="mso-fareast-language:EN-US">Finally, but this is just a comment: this is not â€œflat” mode but nested mode (the code returns a decorator that returns a function
 wrapper)<o:p></o:p></span></li></ul>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">So if I’m not misleading, the problem is not really solved. Or at least, not the way I would like the problem to be solved : it is solved here (a) only if the developer takes extra care
 and (b) reduces the way the decorator can be used (no positional args). This is precisely because I was frustrated by all these limitations that depend on the desired signature that I wrote decopatch. As a developer I do not want to care about which trick
 to use in which situation (mandatory args, optional args, var-positional args..). My decorators may change signature during the development cycle, and if I frequently had to change trick during development as I changed the signature - that is a bit tiring.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">--<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Concerning creation of signature-preserving wrappers:
</span><span lang="EN-US" style="font-size:10.0pt;font-family:"Courier New"">@wrapt.decorator</span><span lang="EN-US" style="mso-fareast-language:EN-US"> is not signature preserving, I just checked it. You can check it with the following experiment:<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<pre style="background:white"><b><span lang="EN-US" style="color:navy">def </span></b><span lang="EN-US" style="color:black">dummy(wrapped):<br>    </span><span lang="EN-US" style="color:#0000B2">@wrapt.decorator<br>    </span><b><span lang="EN-US" style="color:navy">def </span></b><span lang="EN-US" style="color:black">wrapper(wrapped, </span><span lang="EN-US" style="color:gray">instance</span><span lang="EN-US" style="color:black">, args, kwargs):<br>        </span><span lang="EN-US" style="color:navy">print</span><span lang="EN-US" style="color:black">(</span><b><span lang="EN-US" style="color:teal">"wrapper called"</span></b><span lang="EN-US" style="color:black">)<br>        </span><b><span lang="EN-US" style="color:navy">return </span></b><span lang="EN-US" style="color:black">wrapped(*args, **kwargs)<br>    </span><b><span lang="EN-US" style="color:navy">return </span></b><span lang="EN-US" style="color:black">wrapper(wrapped)<o:p></o:p></span></pre>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<pre style="background:white"><span lang="EN-US" style="color:#0000B2">@dummy<br></span><b><span lang="EN-US" style="color:navy">def </span></b><span lang="EN-US" style="color:black">function(</span><span lang="EN-US" style="color:gray">a</span><span lang="EN-US" style="color:black">, </span><span lang="EN-US" style="color:gray">b</span><span lang="EN-US" style="color:black">):<br>    </span><b><span lang="EN-US" style="color:navy">pass</span></b><span lang="EN-US" style="color:black"><o:p></o:p></span></pre>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">If you call
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<pre style="background:white"><span style="color:black">function(</span><span style="color:blue">1</span><span style="color:black">)<o:p></o:p></span></pre>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">you will see that â€œwrapper called” is displayed before the TypeError is raised…<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">The signature-preserving equivalent of
</span><span lang="EN-US" style="color:#0000B2">@wrapt.decorator, @decorator.decorator,
</span><span lang="EN-US" style="mso-fareast-language:EN-US">is the source of inspiration for makefun. You can see `makefun` as a generalization of the core of `decorator`.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">--<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">> </span>
<span lang="EN-US">I'm not sure I ever want them (decopatch and makefun) independently in practice</span><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">I totally understand.
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">But some projects actually need makefun and not decopatch because their need is different: they just want to create a function dynamically. This is low-level tooling, really.<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">So at least now there is a clear separation of concerns (and dedicated issues management/roadmap, which is also quite convenient. Not to mention readability !).<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">To cover your concern: decopatch depends on makefun, so both come at the same time when you install decopatch, and decopatch by default relies on makefun when you use it in â€œdouble-flat”
 mode to create wrappers as explained here</span><span lang="EN-US"> </span><span lang="EN-US" style="mso-fareast-language:EN-US"><a href="https://smarie.github.io/python-decopatch/#even-simpler">https://smarie.github.io/python-decopatch/#even-simpler</a>
<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">--<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Thanks again for this discussion! It is challenging but it is necessary, to make sure I did not answer a non-existent need ;)<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Kind regards<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US"><o:p> </o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">--<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="mso-fareast-language:EN-US">Sylvain<o:p></o:p></span></p>
<p class="MsoNormal"><span lang="EN-US" style="font-size:10.0pt;font-family:"Arial",sans-serif"><o:p> </o:p></span></p>
<div>
<div style="border:none;border-top:solid #E1E1E1 1.0pt;padding:3.0pt 0cm 0cm 0cm">
<p class="MsoNormal"><b><span lang="EN-US">De :</span></b><span lang="EN-US"> David Mertz <mertz@gnosis.cx>
<br>
<b>Envoyé :</b> mardi 12 mars 2019 15:30<br>
<b>À :</b> Sylvain MARIE <sylvain.marie@se.com><br>
<b>Cc :</b> Steven D'Aprano <steve@pearwood.info>; python-ideas <python-ideas@python.org><br>
<b>Objet :</b> Re: [Python-ideas] Problems (and solutions?) in writing decorators<o:p></o:p></span></p>
</div>
</div>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
<p><span lang="EN-US" style="color:red">[External email: Use caution with links and attachments]</span><span lang="EN-US"><o:p></o:p></span></p>
<div class="MsoNormal" align="center" style="text-align:center">
<hr size="3" width="100%" align="center">
</div>
<p><span lang="EN-US"> <o:p></o:p></span></p>
<div>
<div>
<div>
<p class="MsoNormal"><span lang="EN-US">The documentation for wrapt mentions: <o:p>
</o:p></span></p>
<div>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
</div>
<div>
<h2 style="margin-top:0cm;background:#FCFCFC"><span lang="EN-US" style="font-family:"Georgia",serif;color:#404040">Decorators With Optional Arguments<o:p></o:p></span></h2>
<p style="mso-margin-top-alt:0cm;margin-right:0cm;margin-bottom:18.0pt;margin-left:0cm;line-height:18.0pt;background:#FCFCFC">
<span lang="EN-US" style="font-size:12.0pt;font-family:"Arial",sans-serif;color:#404040">Although opinion can be mixed about whether the pattern is a good one, if the decorator arguments all have default values, it is also possible to implement decorators which
 have optional arguments. <o:p></o:p></span></p>
</div>
<p class="MsoNormal"><span lang="EN-US">As Graham hints in his docs, I think repurposing decorator factories as decorators is an antipattern. Explicit is better than implicit.<o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span lang="EN-US">While I *do* understands that what decotools and makefun do are technically independent, I'm not sure I ever want them independently in practice. I did write the book _Functional Programming
 in Python_, so I'm not entirely unfamiliar with function wrappers.<o:p></o:p></span></p>
<div>
<div>
<p class="MsoNormal"><span lang="EN-US">On Tue, Mar 12, 2019, 10:18 AM David Mertz <</span><a href="mailto:mertz@gnosis.cx"><span lang="EN-US">mertz@gnosis.cx</span></a><span lang="EN-US">> wrote:<o:p></o:p></span></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-top:5.0pt;margin-right:0cm;margin-bottom:5.0pt">
<div>
<div>
<p class="MsoNormal"><span lang="EN-US">The wrapt module I linked to (not funtools.wraps) provides all the capabilities you mention since 2013. It allows mixed use of decorators as decorator factories. It has a flat style. <o:p></o:p></span></p>
</div>
<div>
<p class="MsoNormal"><span lang="EN-US"><o:p> </o:p></span></p>
</div>
<div>
<p class="MsoNormal" style="margin-bottom:12.0pt"><span lang="EN-US">There are some minor API difference between your libraries and wrapt, but the concept is very similar. Since yours is something new, I imagine you perceive some win over what wrapt does.<o:p></o:p></span></p>
<div>
<div>
<p class="MsoNormal"><span lang="EN-US">On Tue, Mar 12, 2019, 9:52 AM Sylvain MARIE <</span><a href="mailto:sylvain.marie@se.com" target="_blank"><span lang="EN-US">sylvain.marie@se.com</span></a><span lang="EN-US">> wrote:<o:p></o:p></span></p>
</div>
<blockquote style="border:none;border-left:solid #CCCCCC 1.0pt;padding:0cm 0cm 0cm 6.0pt;margin-left:4.8pt;margin-top:5.0pt;margin-right:0cm;margin-bottom:5.0pt">
<p class="MsoNormal"><span lang="EN-US">David, Steven,<br>
<br>
Thanks for your interest !<br>
<br>
As you probably know, decorators and function wrappers are *completely different concepts*. A decorator can directly return the decorated function (or class), it does not have to return a wrapper. Even more, it can entirely replace the decorated item with something
 else (not even a function or class!). Try it: it is possible to write a decorator to replace a function with an integer, even though it is probably not quite useful :)<br>
<br>
`decopatch` helps you write decorators, whatever they are. It "just" solves the annoying issue of having to handle the no-parenthesis and with-parenthesis calls. In addition as a 'goodie', it proposes two development styles: *nested* (you have to return a function)
 and *flat* (you directly write what will happen when the decorator is applied to something).<br>
--<br>
Now about creating signature-preserving function wrappers (in a decorator, or outside a decorator - again, that's not related). That use case is supposed to be covered by functools.wrapt. Unfortunately as explained here
</span><a href="https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fstackoverflow.com%2Fquestions%2F308999%2Fwhat-does-functools-wraps-do%2F55102697%2355102697&data=02%7C01%7Csylvain.marie%40se.com%7Ca7dee43a3bdf494e37c508d6a6f73f7d%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879978186393926&sdata=Dmkd0Ld1HsuCJtJDCS6GDUgwH3GO66zwYMpZ9Ow%2B18k%3D&reserved=0" target="_blank"><span lang="EN-US">https://stackoverflow.com/questions/308999/what-does-functools-wraps-do/55102697#55102697</span></a><span lang="EN-US">
 this is not the case because with functools.wrapt:<br>
 - the wrapper code will execute even when the provided arguments are invalid.<br>
 - the wrapper code cannot easily access an argument using its name, from the received *args, **kwargs. Indeed one would have to handle all cases (positional, keyword, default) and therefore to use something like Signature.bind().<br>
<br>
For this reason I proposed a replacement in `makefun`: </span><a href="https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsmarie.github.io%2Fpython-makefun%2F%23signature-preserving-function-wrappers&data=02%7C01%7Csylvain.marie%40se.com%7Ca7dee43a3bdf494e37c508d6a6f73f7d%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879978186403936&sdata=SO319cmnKXiUK6Zek%2FSioHIhFfnQCZRpAF3kim84mv8%3D&reserved=0" target="_blank"><span lang="EN-US">https://smarie.github.io/python-makefun/#signature-preserving-function-wrappers</span></a><span lang="EN-US">
<br>
--<br>
Now bridging the gap. Of course a very interesting use cases for decorators is to create decorators that create a signature-preserving wrapper. It is possible to combine decopatch and makefun for this:
</span><a href="https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsmarie.github.io%2Fpython-decopatch%2F%233-creating-function-wrappers&data=02%7C01%7Csylvain.marie%40se.com%7Ca7dee43a3bdf494e37c508d6a6f73f7d%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879978186403936&sdata=FpCGLYwJHFJMWmStJhI%2F7NzXxmJPwC3hf9afg2zfXik%3D&reserved=0" target="_blank"><span lang="EN-US">https://smarie.github.io/python-decopatch/#3-creating-function-wrappers</span></a><span lang="EN-US">
 .<br>
Decopatch even proposes a "double-flat" development style where you directly write the wrapper body, as explained in the doc.<br>
<br>
Did I answer your questions ?<br>
Thanks again for the quick feedback !<br>
Best,<br>
<br>
Sylvain <br>
<br>
-----Message d'origine-----<br>
De : Python-ideas <python-ideas-bounces+sylvain.marie=</span><a href="mailto:se.com@python.org" target="_blank"><span lang="EN-US">se.com@python.org</span></a><span lang="EN-US">> De la part de Steven D'Aprano<br>
Envoyé : mardi 12 mars 2019 12:30<br>
À : </span><a href="mailto:python-ideas@python.org" target="_blank"><span lang="EN-US">python-ideas@python.org</span></a><span lang="EN-US"><br>
Objet : Re: [Python-ideas] Problems (and solutions?) in writing decorators<br>
<br>
[External email: Use caution with links and attachments]<br>
<br>
________________________________<br>
<br>
<br>
<br>
On Tue, Mar 12, 2019 at 09:36:41AM +0000, Sylvain MARIE via Python-ideas wrote:<br>
<br>
> I therefore proposed<br>
> </span><a href="https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsma" target="_blank"><span lang="EN-US">https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fsma</span></a><span lang="EN-US"><br>
> </span><a href="https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Frie.github.io&data=02%7C01%7Csylvain.marie%40se.com%7Ca7dee43a3bdf494e37c508d6a6f73f7d%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879978186413941&sdata=8QNKZapq0Z9VQtREcqt4f8EcKbTteHWqiAhD1kVnDyc%3D&reserved=0" target="_blank"><span lang="EN-US">rie.github.io</span></a><span lang="EN-US">%2Fpython-makefun%2F&amp;data=02%7C01%7Csylvain.marie%40s<br>
> </span><a href="https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fe.com&data=02%7C01%7Csylvain.marie%40se.com%7Ca7dee43a3bdf494e37c508d6a6f73f7d%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879978186413941&sdata=73ekIlXJ7nwxcsHYz91JotQ%2F0eGH7h6YC2e3U5pqXow%3D&reserved=0" target="_blank"><span lang="EN-US">e.com</span></a><span lang="EN-US">%7C579232e7e10e475314c708d6a6de9d23%7C6e51e1adc54b4b39b5980ffe9ae<br>
> 68fef%7C0%7C0%7C636879872385158085&amp;sdata=nB9p9V%2BJ7gk%2Fsc%2BA5%2<br>
> Fekk35bnYGvmEFJyCXaLDyLm9I%3D&amp;reserved=0 . In particular it <br>
> provides an equivalent of `@functools.wraps` that is truly <br>
> signature-preserving<br>
<br>
Tell us more about that please. I'm very interested in getting decorators preserve the original signature.<br>
<br>
<br>
--<br>
Steven<br>
_______________________________________________<br>
Python-ideas mailing list<br>
</span><a href="mailto:Python-ideas@python.org" target="_blank"><span lang="EN-US">Python-ideas@python.org</span></a><span lang="EN-US"><br>
</span><a href="https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Fpython-ideas&data=02%7C01%7Csylvain.marie%40se.com%7Ca7dee43a3bdf494e37c508d6a6f73f7d%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879978186423950&sdata=X1o6EwD3M3jw6n%2Fqrsx0IFoBK8N2nsoSq4nKDgcmAZQ%3D&reserved=0" target="_blank"><span lang="EN-US">https://emea01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fmail.python.org%2Fmailman%2Flistinfo%2Fpython-ideas&amp;data=02%7C01%7Csylvain.marie%40se.com%7C579232e7e10e475314c708d6a6de9d23%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879872385158085&amp;sdata=XcYfEginmDF7kIpGGA0XxDZKpUn9e4p2zPFk7UAruYg%3D&amp;reserved=0</span></a><span lang="EN-US"><br>
Code of Conduct: </span><a href="https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpython.org%2Fpsf%2Fcodeofconduct%2F&data=02%7C01%7Csylvain.marie%40se.com%7Ca7dee43a3bdf494e37c508d6a6f73f7d%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879978186423950&sdata=gatcCdLn8s9Zhh26txhKRsqHIYkKpEghOTNmVJ%2BDZJw%3D&reserved=0" target="_blank"><span lang="EN-US">https://emea01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fpython.org%2Fpsf%2Fcodeofconduct%2F&amp;data=02%7C01%7Csylvain.marie%40se.com%7C579232e7e10e475314c708d6a6de9d23%7C6e51e1adc54b4b39b5980ffe9ae68fef%7C0%7C0%7C636879872385158085&amp;sdata=20ZrtVQZbpQ54c96veSXIOfEK7rKy0ggj0omTZg3ri8%3D&amp;reserved=0</span></a><span lang="EN-US"><br>
<br>
______________________________________________________________________<br>
This email has been scanned by the Symantec Email Security.cloud service.<br>
______________________________________________________________________<o:p></o:p></span></p>
</blockquote>
</div>
</div>
</div>
</blockquote>
</div>
</div>
</div>
<p class="MsoNormal"><span lang="EN-US"><br>
______________________________________________________________________<br>
This email has been scanned by the Symantec Email Security.cloud service.<br>
</span>______________________________________________________________________<o:p></o:p></p>
</div>
</div>
</body>
</html>