Path: csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail From: Hynek Schlawack Newsgroups: comp.lang.python.announce Subject: attrs 16.3.0 Date: Sat, 26 Nov 2016 14:57:13 +0100 Lines: 104 Approved: python-announce-list@python.org Message-ID: References: <7E9768D4-19F0-4591-B8E0-6B4AB10FC6A7@ox.cx> Mime-Version: 1.0 (Mac OS X Mail 10.1 \(3251\)) Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Trace: news.uni-berlin.de c8FYh36feBvuyDAzXg7OnQfXdlpHBZgdYyXpDgWzYshA== Return-Path: X-Original-To: python-announce-list@python.org Delivered-To: python-announce-list@mail.python.org X-Spam-Status: OK 0.000 X-Spam-Evidence: '*H*': 1.00; '*S*': 0.00; 'url:pypi': 0.03; '__name__': 0.05; 'i\xe2\x80\x99m': 0.05; 'method.': 0.05; 'url:github': 0.05; 'attributes': 0.07; 'classes.': 0.07; 'lines.': 0.07; 'pypi': 0.07; 'received:internal': 0.07; 'python': 0.09; "'__main__':": 0.09; '===========': 0.09; '__init__': 0.09; 'hooks': 0.09; 'i\xe2\x80\x99d': 0.09; 'overwrite': 0.09; 'received:10.202': 0.09; 'received:10.202.2': 0.09; 'received:66.111': 0.09; 'received:66.111.4': 0.09; 'received:messagingengine.com': 0.09; 'url:issues': 0.09; 'variables': 0.15; '<>)': 0.16; 'attrs': 0.16; 'github:': 0.16; 'himself.': 0.16; 'magic': 0.16; 'metadata.': 0.16; 'optionally': 0.16; 'skip:@ 20': 0.16; 'subclassing': 0.16; 'url:project': 0.16; 'user-defined': 0.16; 'attribute': 0.18; 'skip:p 40': 0.18; 'runs': 0.18; 'library': 0.20; 'tried': 0.21; 'defined': 0.21; 'load': 0.21; 'exceptions': 0.22; 'it\xe2\x80\x99s': 0.22; 'users,': 0.22; 'skip:e 30': 0.23; 'cheers,': 0.24; 'skip:= 10': 0.24; 'feature': 0.25; 'written': 0.27; 'example': 0.29; 'improves': 0.29; 'struct': 0.29; 'announce': 0.29; 'classes': 0.30; 'code': 0.30; 'define': 0.30; 'extend': 0.31; 'post': 0.31; 'option': 0.31; 'allows': 0.32; 'everyone': 0.33; 'running': 0.33; 'point': 0.33; 'skip:= 20': 0.33; 'method': 0.33; 'two': 0.34; 'but': 0.34; 'skip:v 20': 0.35; 'instead': 0.35; 'release': 0.35; 'useful': 0.35; 'class': 0.35; 'there': 0.36; 'end': 0.36; 'url:org': 0.36; 'still': 0.36; 'add': 0.36; 'should': 0.36; 'others.': 0.36; 'skip:_ 10': 0.36; 'third': 0.36; 'version': 0.37; 'gives': 0.37; 'greatly': 0.37; 'why': 0.38; 'received:10': 0.38; 'received:66': 0.39; 'to:addr:python.org': 0.39; 'skip:e 20': 0.39; 'proto:https': 0.40; 'called': 0.40; 'received:192': 0.40; 'received:io': 0.40; 'received:psf.io': 0.40; 'behavior': 0.60; 'address': 0.61; 'default': 0.61; 'per': 0.62; 'header :Message-Id:1': 0.62; 'dear': 0.63; 'enthusiastic': 0.66; '\xe2\x80\x93': 0.68; 'life': 0.69; '100%': 0.71; 'to:addr:python- announce-list': 0.71; 'tags,': 0.79; 'you:': 0.79; 'again!': 0.84; 'areas.': 0.84; 'refresher': 0.84; 'url:2016': 0.84; 'url:config': 0.84; 'exposing': 0.91; '\xe2\x80\x9cthe': 0.93 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding:content-type :date:from:message-id:mime-version:subject:to:x-me-sender :x-me-sender:x-sasl-enc:x-sasl-enc; s=smtpout; bh=nFQlztz3mRvsCV vQ3TH+GP+Vdu0=; b=ATtBpiDeZa2z1FA8NNnxYok+iE246F5T+CKhGcJE5Q964b dNLmUnPYdtBM5SUMpg+letx3f1ugV5sDTYPfrFBBN7C6sOErOSVaUhPuJhC9I4pe UT5ntggUTUjwoeRQDqmbko8AUr4PIclxkhsJq6y4m2x+CeLeZTtSBXt8ZxACo= X-ME-Sender: X-Sasl-enc: nqZ+15sO0TVLALIY50Txf+pxAl91/25JUsM6OpHM62fy 1480168635 X-Mailer: Apple Mail (2.3251) X-Mailman-Approved-At: Sat, 26 Nov 2016 13:20:31 -0500 X-BeenThere: python-announce-list@python.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Announcement-only list for the Python programming language List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Mailman-Original-Message-ID: <7E9768D4-19F0-4591-B8E0-6B4AB10FC6A7@ox.cx> Xref: csiph.com comp.lang.python.announce:2326 Dear fellow Pythonistas, I=E2=80=99m very happy to announce attrs 16.3.0, the Python library the = makes you love writing classes again! If you need a refresher why you = should use attrs, have a look at =E2=80=9CThe One Python Library = Everyone Needs=E2=80=9D = written by no one = less than Glyph himself. It=E2=80=99s still 100% free of magic but 100% full of convenience! This version comes with two major new features I=E2=80=99d like to point = out: 1. Attribute Metadata =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D There is a much nicer way to extend attrs now by using attribute = metadata. If you=E2=80=99re thinking Golang=E2=80=99s struct tags, = it=E2=80=99s close! However instead of exposing them to the users, it=E2=80=99s much nicer = to *wrap* attrs and use metadata to bring the declarative approach to = new areas. For example this code will automatically load its configuration from env = variables (as per 12Factor App: ): ``` @app_config(prefix=3D"APP", vault_prefix=3D"WHOIS_{env}") class WhoisConfig: @app_config class Prometheus: address =3D env_var(default=3D"127.0.0.1") port =3D env_var(default=3D"0") consul_token =3D env_var_from_vault() env =3D env_var() prometheus =3D env_var_group(Prometheus) if __name__ =3D=3D '__main__': ac =3D environ_to_app_config(WhoisConfig) print(ac) ``` Running it gives you: ``` $ env APP_ENV=3Ddev APP_PROMETHEUS_PORT=3D7000 = SECRET_WHOIS_DEV_APP_PROMETHEUS_CONSUL_TOKEN=3Dabc python app.py WhoisConfig(env=3D'dev', prometheus=3DPrometheus(address=3D'127.0.0.1', = port=3D'7000', consul_token=3D'abc')) ``` (If you=E2=80=99re interested in the implementation of app_config, = env_var, env_var_from_vault, env_var_group, and environ_to_app_config, = have a look at = =E2=80=93= it=E2=80=99s 87 LoC including empty lines. I may or may not release a = PyPI package one day) 2. Post Initialization Hooks =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D This is an often requested feature (just look at all those enthusiastic = bikeshed painters: ) and = allows you to define code that runs after the generated __init__ method. This should make life easier when subclassing third party classes or if = you want to derive attributes from others. Full Changelog =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D - Attributes now can have user-defined metadata which greatly improves = attrs's extensibility. #96 - Allow for a __attrs_post_init__ method that -- if defined -- will = get called at the end of the attrs-generated __init__ method. #111 - Add @attr.s(str=3DTrue) that will optionally create a __str__ method = that is identical to __repr__. This is mainly useful with Exceptions and = other classes that rely on a useful __str__ implementation but overwrite = the default one through a poor own one. Default Python class behavior is = to use __repr__ as __str__ anyways. If you tried using attrs with Exceptions and were puzzled by the = tracebacks: this option is for you. - Don't overwrite __name__ with __qualname__ for attr.s(slots=3DTrue) = classes. #99 Links =3D=3D=3D=3D PyPI: Documentation: GitHub: Cheers, Hynek=