Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #83610

Re: class-based class decorator

Path csiph.com!usenet.pasdenom.info!aioe.org!news.stack.nl!newsfeed.xs4all.nl!newsfeed3.news.xs4all.nl!xs4all!post.news.xs4all.nl!not-for-mail
Return-Path <fomcl@yahoo.com>
X-Original-To python-list@python.org
Delivered-To python-list@mail.python.org
X-Spam-Status OK 0.000
X-Spam-Evidence '*H*': 1.00; '*S*': 0.00; 'url:pypi': 0.03; 'parameters': 0.04; 'warnings': 0.04; 'argument': 0.05; 'class,': 0.07; 'defaults': 0.07; 'modify': 0.07; '"__main__":': 0.09; '*args,': 0.09; '__init__': 0.09; '__name__': 0.09; 'arguments': 0.09; 'builtin': 0.09; 'decorator': 0.09; 'default.': 0.09; 'deprecated': 0.09; 'method,': 0.09; 'msg': 0.09; 'obsolete': 0.09; 'sphinx': 0.09; 'used.': 0.09; 'python': 0.11; 'def': 0.12; 'jan': 0.12; '2.7': 0.14; '"hello': 0.16; '**kwargs)': 0.16; '**kwargs):': 0.16; '*args': 0.16; 'argument.': 0.16; 'chris,': 0.16; 'foo(object):': 0.16; 'intended.': 0.16; 'non-default': 0.16; 'param': 0.16; 'subject:based': 0.16; 'subject:class': 0.16; 'unbound': 0.16; 'url.': 0.16; 'wrote:': 0.18; '(not': 0.18; 'trying': 0.19; 'skip:f 30': 0.19; '(the': 0.22; 'appears': 0.22; 'import': 0.22; '(in': 0.22; 'print': 0.22; 'module,': 0.24; 'specify': 0.24; 'pass': 0.26; 'values': 0.27; 'gets': 0.27; 'header:In-Reply-To:1': 0.27; 'to:2**1': 0.27; 'function': 0.29; "doesn't": 0.30; 'included': 0.31; 'code': 0.31; 'inspect': 0.31; 'prints': 0.31; 'values.': 0.31; 'class': 0.32; 'skip:c 30': 0.32; 'regular': 0.32; 'up.': 0.33; 'url:python': 0.33; '-----': 0.33; 'becomes': 0.33; 'fri,': 0.33; 'period': 0.33; 'skip:_ 10': 0.34; 'skip:d 20': 0.34; 'problem': 0.35; 'but': 0.35; 'there': 0.35; 'wishes,': 0.36; 'thanks': 0.36; 'hi,': 0.36; 'url:org': 0.36; 'should': 0.36; 'january': 0.37; 'checks': 0.38; 'needed': 0.38; 'to:addr:python-list': 0.38; 'pm,': 0.38; 'subject:': 0.39; 'to:addr:python.org': 0.39; 'changed': 0.39; 'how': 0.40; 'even': 0.60; 'ian': 0.60; 'received:67.195': 0.60; 'received:98.137': 0.60; 'most': 0.60; 'lost': 0.61; 'here:': 0.62; "you'll": 0.62; 'complete': 0.62; 'information': 0.63; 're:': 0.63; 'kind': 0.63; 'such': 0.63; 'map': 0.64; 'more': 0.64; 'to:addr:gmail.com': 0.65; 'header:Reply-To:1': 0.67; 'received:gq1.yahoo.com': 0.68; 'received:mail.gq1.yahoo.com': 0.68; 'skip:w 30': 0.69; 'default': 0.69; 'hoping': 0.75; '2015': 0.84; 'affected.': 0.84; 'code):': 0.84; 'hardly': 0.84; 'ian,': 0.84; 'received:bullet.mail.gq1.yahoo.com': 0.84; 'replies.': 0.84; 'package:': 0.93
DKIM-Signature v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.com; s=s2048; t=1421070449; bh=3Zf5jhErPTrh9phB+UM+rCZ+mNhMvBF2vY/Fpm+n1Aw=; h=Date:From:Reply-To:To:In-Reply-To:References:Subject:From:Subject; b=qLReCt0Mja7//F8BbOYPu0wSJjCgnjBi6cfxY+U7J/b8fmmYdvCIqv6WqDgnxgC2K64nt8qHoowH0/JcHiK8aesJrMyZN8rQMMy7SHLB21NJVRO+XsmuqAcH3YS4x6yZNcr8NWUKPlLP9+uD2DNBid/wkixb4x8AZ8hl6B7Nd615vQqidTq16q5Hm6bgldJHm7ti8kRYMGyH1oVvWravaq3uzR/atLH+zor1rMYwEvMKws5bwEwQeAQKVHt7UI6gEWd4WGJXJNEGsf7nuY+Geyy+PDZ7zJ2zefi9NZM3mdgLqXQS3a2WFbJmsUHd0sVULUs7NPe/miT4BsZEbUaoiA==
DomainKey-Signature a=rsa-sha1; q=dns; c=nofws; s=s2048; d=yahoo.com; b=dXXaCb55vCOyjnl8bTXDooYv69wvQrlSitN26yl9r5xYNwftQpZ+lDpTee4fqAyvAN5G+wN3EhKq3eoFYvEbzpGYThBNIH+mEDeel27tShL3ifwPmwDeZAZr8PQGBkFiBZIIGwd3Y3EDStSA/VOnmioKwkioQFZfHpDbLLMolTW0er/68PridGg1P3zmfsf9OmvP5tu/dCYc1UkqngqZVVkI9v0RJEhXJ/F7mKnB9EAvyEPIH4UAoJVDzTZgQOaUPT05UM7NU+Bdje+jck52joYxPiiTyiAwlBiA26XXB3N8KnJ2ubeiIZ9k5CN/28WLgzB4BQ91EmNPms3N3rItnA==;
X-Yahoo-Newman-Property ymail-4
X-Yahoo-Newman-Id 904249.58128.bm@omp1001.mail.gq1.yahoo.com
X-YMail-OSG gSqFiqAVM1mr1JZA4A1oleiRBiAOKp_doDWWN_ouK5NN6tNuf1iC0NeO0Q5D4As x3OPodg4PhwziR9.do3ZOXCphKEYOwCjjquO8Qh6zI7CAFOsq4wqgcjH33Qe5o5v.I.Cyo7nRuBe bL54x8mb.UlhQ5uKRVXRwhoYcA4j_j_c0f9SR5uUe01g4YDpm_UlnfebOOJvhQ9MYRSzzY0C_S.i glGYBmmq01QmQkmpmarbcSXsH99r2hkP47.9nY58V.KNWDWMncti0G6g3joJ1DZ.nGZNnZsPk2mM 6qf.Q5dwLgbz19KEagW5Pd8Wpw7ooSr8OEfqwXrNwyMbPYsGNYepee.petEO_Zb6NonrSZrXLV9W ZMlby61uMoO5Z5hNHabMvSi5p2Oqp75DRcJWIzJZ3.Yq7G1hgvvakQUQeX9Se7KeY3sUpn4Oaf6i ldfNTUBc6LMsnjgPJM9rUrKlTp9Enk2yR3AOUl8NHRvKWBA7whVBvDxv5IRH5.NuRdd9gW2wQBg8 H_iKeM64eXdHxfZjl2m5zkKq972zPDVtO6iFBAX4HCgZqJUdOlYsiq7s_RlDsyqTogIOiv1_dvR8 nY8cLhTM-
Date Mon, 12 Jan 2015 13:44:36 +0000 (UTC)
From Albert-Jan Roskam <fomcl@yahoo.com>
To Ian Kelly <ian.g.kelly@gmail.com>, Python <python-list@python.org>
In-Reply-To <CALwzidkvGKEJtZ2f2LyfA4atY0kpaQsGrCtBro5X2TyrBe98Hw@mail.gmail.com>
References <CALwzidkvGKEJtZ2f2LyfA4atY0kpaQsGrCtBro5X2TyrBe98Hw@mail.gmail.com>
Subject Re: class-based class decorator
MIME-Version 1.0
Content-Type text/plain; charset=UTF-8
Content-Transfer-Encoding 7bit
X-BeenThere python-list@python.org
X-Mailman-Version 2.1.15
Precedence list
Reply-To Albert-Jan Roskam <fomcl@yahoo.com>
List-Id General discussion list for the Python programming language <python-list.python.org>
List-Unsubscribe <https://mail.python.org/mailman/options/python-list>, <mailto:python-list-request@python.org?subject=unsubscribe>
List-Archive <http://mail.python.org/pipermail/python-list/>
List-Post <mailto:python-list@python.org>
List-Help <mailto:python-list-request@python.org?subject=help>
List-Subscribe <https://mail.python.org/mailman/listinfo/python-list>, <mailto:python-list-request@python.org?subject=subscribe>
Newsgroups comp.lang.python
Message-ID <mailman.17623.1421070586.18130.python-list@python.org> (permalink)
Lines 97
NNTP-Posting-Host 2001:888:2000:d::a6
X-Trace 1421070586 news.xs4all.nl 2878 [2001:888:2000:d::a6]:52430
X-Complaints-To abuse@xs4all.nl
Xref csiph.com comp.lang.python:83610

Show key headers only | View raw



----- Original Message -----

> From: Ian Kelly <ian.g.kelly@gmail.com>
> To: Python <python-list@python.org>
> Cc: 
> Sent: Saturday, January 10, 2015 7:30 AM
> Subject: Re: class-based class decorator
> 
> On Fri, Jan 9, 2015 at 2:26 PM, Albert-Jan Roskam
> 
> <fomcl@yahoo.com.dmarc.invalid> wrote:
>> 
>> 
>>  Hi,
>> 
>>  I am trying to write a class decorator that checks whether deprecated 
> parameters with non-default
>> 
>>  arguments are used. More complete code is here: 

> http://pastebin.com/ZqnMis6M.

Oops, the period was included in the url. It was 
http://pastebin.com/ZqnMis6M

>> In the code below,>>  how should I modify __call__ such that f.bar(old="oh no") prints 
> "hello world"?
>>  I thought it would be a fun way to play with the inspect module, but my 
> head is numb now and I am thirsty for a beer!
> 
> You can use inspect.getargspec to look up the default argument values
> for the target function. You can use inspect.getcallargs to map your
> *args and **kwargs to a dictionary of argument names and values. Since
> the target function will be the unbound __init__ method, you'll also
> want to pass in a dummy value like None for the self argument. Then
> you just look up each of the deprecated names in the result and flag
> any where the value doesn't match the default.
> 
> If you were using Python 3.3+, then I would recommend using
> inspect.signature instead, which is a lot more powerful. But your code
> appears to be Python 2, so we work with what we've got.


Hi Ian, Chris,

Thanks for your replies. I changed it into a regular decorator (not a class decorator). It would have been even nicer if I only needed to specify it once per class, but, well, in my case this hardly matters. The code below works as intended. One problem (not specific to the code): the decorator destroys the signature: it always becomes "*args, **kwargs"). This is annoying with help(), but what worries me most is that my Sphinx documentation is also affected. The information about the defaults gets lost (the parameters are decribed in the docstring, but not the defaults). That kind of sucks. Is there a builtin way around this (in other words: I am aware of this package: https://pypi.python.org/pypi/decorator). I am hoping to get the code working on Python 2.7 and 3.3 and up.

import functools
import inspect
import warnings

warnings.simplefilter("always")

class check_deprecated_args(object):

    def __init__(self, deprecated_params, msg=None):
        self.deprecated_params = deprecated_params
        self.msg = msg

    def __call__(self, func):
        @functools.wraps(func)
        def inner(*args, **kwargs):
            argspec = inspect.getargspec(func)
            default_signature = dict(zip(argspec.args[1:], argspec.defaults))
            callargs = inspect.getcallargs(func, *args, **kwargs)
            deprecated_calls = [(p, a) for p, a in callargs.items() if 
                                 p in self.deprecated_params and 
                                 a != default_signature[p]]
            for (param, arg) in deprecated_calls:
                msg = "you're using obsolete parameters in %s: [%s:%s]" 
                msg = msg % (func.__name__, param, arg)
                msg = msg + " " + self.msg if self.msg else msg 
                warnings.warn(msg, DeprecationWarning, stacklevel=2)
            return func(*args, **kwargs)
        functools.update_wrapper(inner, func)
        return inner

if __name__ == "__main__":
    class Foo(object):

        @check_deprecated_args(["old", "older"], "use 'brand_new' param instead")
        def __init__(self, old="old", older="ancient"):
            print "hello"

        @check_deprecated_args(deprecated_params=["old", "older"])
        def bar(self, old="default"):
            print "world"    

    f = Foo(old="old", older="dino era")
    f.bar("gnarly")

    help(f)  # now the signature is *args, **kwargs, which makes my Sphinx documentation less readable!

Best wishes,
Albert-Jan

Back to comp.lang.python | Previous | Next | Find similar | Unroll thread


Thread

Re: class-based class decorator Albert-Jan Roskam <fomcl@yahoo.com> - 2015-01-12 13:44 +0000

csiph-web