Python Classes Without Boilerplate

attrs

Documentation Status CI Status Test Coverage Code style: black

attrs is the Python package that will bring back the joy of writing classes by relieving you from the drudgery of implementing object protocols (aka dunder methods).

Its main goal is to help you to write concise and correct software without slowing down your code.

For that, it gives you a class decorator and a way to declaratively define the attributes on that class:

>>> import attr

>>> @attr.s
... class SomeClass(object):
...     a_number = attr.ib(default=42)
...     list_of_numbers = attr.ib(factory=list)
...
...     def hard_math(self, another_number):
...         return self.a_number + sum(self.list_of_numbers) * another_number


>>> sc = SomeClass(1, [1, 2, 3])
>>> sc
SomeClass(a_number=1, list_of_numbers=[1, 2, 3])

>>> sc.hard_math(3)
19
>>> sc == SomeClass(1, [1, 2, 3])
True
>>> sc != SomeClass(2, [3, 2, 1])
True

>>> attr.asdict(sc)
{'a_number': 1, 'list_of_numbers': [1, 2, 3]}

>>> SomeClass()
SomeClass(a_number=42, list_of_numbers=[])

>>> C = attr.make_class("C", ["a", "b"])
>>> C("foo", "bar")
C(a='foo', b='bar')

After declaring your attributes attrs gives you:

  • a concise and explicit overview of the class's attributes,
  • a nice human-readable __repr__,
  • a complete set of comparison methods (equality and ordering),
  • an initializer,
  • and much more,

without writing dull boilerplate code again and again and without runtime performance penalties.

On Python 3.6 and later, you can often even drop the calls to attr.ib() by using type annotations.

This gives you the power to use actual classes with actual types in your code instead of confusing tuples or confusingly behaving namedtuples. Which in turn encourages you to write small classes that do one thing well. Never again violate the single responsibility principle just because implementing __init__ et al is a painful drag.

Getting Help

Please use the python-attrs tag on StackOverflow to get help.

Answering questions of your fellow developers is also a great way to help the project!

Project Information

attrs is released under the MIT license, its documentation lives at Read the Docs, the code on GitHub, and the latest release on PyPI. It’s rigorously tested on Python 2.7, 3.5+, and PyPy.

We collect information on third-party extensions in our wiki. Feel free to browse and add your own!

If you'd like to contribute to attrs you're most welcome and we've written a little guide to get you started!

attrs for Enterprise

Available as part of the Tidelift Subscription.

The maintainers of attrs and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. Learn more.

Owner
The attrs Cabal
Dedicated to empower Python developers to write better code with less effort.
The attrs Cabal
Comments
  • Add PEP484 stubs

    Add PEP484 stubs

    Here's a first take at PEP484-compatible pyi stubs. The discussion in #215 has been mostly focused on runtime type checking, so I wanted to make sure that the plan discussed there will work with static analysis as well.

    Here's a quick test of the stubs that I put together to run against mypy:

    from typing import cast
    import attr
    
    @attr.s
    class C(object):
        x : int = attr.ib(convert=int)
        y: str = attr.ib()
    
    c = C('1', 'foo')  # E: Too many arguments for "C"
    c.x = 2
    c.y = 'bar'
    c > C()  # E: Unsupported left operand type for > ("C")
    str(c)
    
    # errors below are correctly detected:
    c.x = 'foo'  # E: Incompatible types in assignment (expression has type "str", variable has type "int")
    c.y = 1  # E: Incompatible types in assignment (expression has type "int", variable has type "str")
    
    D = attr.make_class('D', {'x': cast(attr._CountingAttr, attr.ib())})
    d = D(2)
    # errors below are not correctly detected (mypy knows nothing about D other than that it's a type)
    d.x ='foo'
    

    mypy knows nothing about the dunder methods added by attrs, so cmp methods and __init__ fail. This will have to be solved with a mypy plugin, which I'll look into next. Same goes for attr.make_class though that's likely to be more difficult.

    One important thing to note: in order to ensure that y: str = attr.ib() does not trigger a mypy error, the return type of attr.ib is Any instead of _CountingAttr. A side effect of this is that it complicates passing the result of attr.ib to functions that expect _CountingAttr instances. There are a handful of strategies to solve this:

    1. use typing.cast: ugly and verbose
    2. create, or choose an existing, alias for attr.ib that will return _CountingAttr, to use with functions like make_class.
    3. add another argument (make=True?) whose presence invokes an @overload of attr.ib that returns _CountingAttr
    4. slight variation on 2. create a public alias for _CountingAttr and copy the keyword defaults from attr.ib to _CountingAttr.__init__. In other words, if you use static type checking and are working with a function that expects _CountingAttr instances, use _CountingAttr() directly instead of attr.ib()

    ~~I favor the 3rd solution.~~ After some consideration I favor 4.

    If you're interested in accepting this, the next things to figure out are:

    • how to make tests for this, and run them on travis
    • how best to install the stubs (should they be moved to python-typeshed?)

    Let me know what you think.

    edit added option 4.

  • init hooks

    init hooks

    Sometimes I want to write an attr.s class that has some behavior in its constructor. Particularly:

    • I want to validate between/among different related values passed to the c'tor
    • I want to establish a bidirectional relationship to one of the arguments passed to the c'tor (for example: protocol/transport hook-up)
    • I want to do some gross I/O because it's a handle for some external gross I/O object (i.e. I want to open something, for example) (sorry)

    Arguably, many of these things could be expressed as a function, but some of them involve preserving valid structural relationships between the object and its dependencies, so I'd really prefer to be able to use __init__ in some cases.

    I know, I can write my own __init__. I know! But if I do that, I give up not just on the convenience of attr.s writing the __init__ for me, but also the useful behavior of attr.s: i.e. validators, default factories.

    All of my use-cases here would be easily accomplished with either a pre-__init__ and post-__init__ hook. Most of the ones I'm actually interested in would all be achievable with a post-__init__ hook; I think pre-__init__ might be pointless given the availability of convert=.

    This has been discussed already, but some of the other issues (#33 #24 #38 #38 #58) which have raised the possibility of a post-__init__ hook have been somewhat conflated with better support for inheritance. As we all know, inheritance is deprecated and will be removed in python 3.7 so we don't need to focus on that.

  • Allow user to customize how an attribute is compared (#435)

    Allow user to customize how an attribute is compared (#435)

    Apologies for resubmitting a PR. I had made a mess in my fork and this was a side-effect.

    The idea of this PR is to add a comparator argument to attr.ib( ), in which the user could provide a simple class implementing equality and ordering methods to suit their needs.

    • [x] Added tests for changed code.
    • [ ] New features have been added to our Hypothesis testing strategy.
    • [x] Changes or additions to public APIs are reflected in our type stubs (files ending in .pyi).
      • [ ] ...and used in the stub test file tests/typing_example.py.
    • [ ] Updated documentation for changed code.
      • [ ] New functions/classes have to be added to docs/api.rst by hand.
      • [ ] Changes to the signature of @attr.s() have to be added by hand too.
      • [x] Changed/added classes/methods/functions have appropriate versionadded, versionchanged, or deprecated directives. Find the appropriate next version in our __init__.py file.
    • [ ] Documentation in .rst files is written using semantic newlines.
    • [x] Changes (and possible deprecations) have news fragments in changelog.d.
  • [RFC] First class type support

    [RFC] First class type support

    This is kind of part of #214 but it stands for itself too.

    Something like:

    @attr.s(check_types=True)
    class C:
        x = attr.ib(type=int)
    

    ought to work.

    Regardless of checking the type, the type information has to be accessible somewhere so we can have first-class deserialization support.

  • [RFC] Inconvenient defaults?

    [RFC] Inconvenient defaults?

    As part of “Projectimport attrs” (see also #408) we get a unique opportunity to change default options/behaviors that grew over the years but couldn't be fixed due to backward-compatibility restrictions.

    The rough plan is create a new, friendlier API on top of @attr.s and attr.ib() that won't go anywhere.

    The following is cast in stone:

    • auto_attribs=True
    • consistent (Python 3-style) hashing behavior on every Python version
    • #428

    The following would be really nice to have:

    • #368 but it might need too much thinking/research

    What else is bugging you?


    One thing that I just can't make up my mind is related to #223: should we make slots=True the default? I’m quite confident that in 99,9% of cases it's the right thing to do and will guide people to write better classes.

    However on the other hand, our approach of rewriting classes breaks in certain scenarios, usually involving metaclasses.

    So the question is, whether we want to tolerate a higher rate of bogus bug reports/help requests or make the default case nicer?

    I welcome your input.


    Finally a controversial idea: we could make import attrs Python 3 only. There isn't much baggage we'd get rid of but there is some and 2020 is less than a year ahead. It would also allow us to embrace enums as part of our API.

  • Find better name for attr.dataclass

    Find better name for attr.dataclass

    So attr.dataclass was meant more or less as a joke, but I just caught myself using it too but the name is bad, because it’s confusing. It implies some kind of symmetry or compatibility to DCs which it doesn’t.

    So here’s a nice bike shed, please help me finding a short, memorable, and meaningful color for it!

  • Improve (de)serialization and validation capabilities

    Improve (de)serialization and validation capabilities

    Improve (de)serialization and validation capabilities by adding hooks that can automatically update a class’ attributes and that can change the way how objects are serialized by asdict().

    See: #649

    Pull Request Check List

    This is just a friendly reminder about the most common mistakes. Please make sure that you tick all boxes. But please read our contribution guide at least once, it will save you unnecessary review cycles!

    If an item doesn't apply to your pull request, check it anyway to make it apparent that there's nothing left to do.

    • [x] Added tests for changed code.
    • [x] New features have been added to our Hypothesis testing strategy.
    • [x] Changes or additions to public APIs are reflected in our type stubs (files ending in .pyi).
      • [x] ...and used in the stub test file tests/typing_example.py.
    • [x] Updated documentation for changed code.
      • [x] New functions/classes have to be added to docs/api.rst by hand.
      • [x] Changes to the signature of @attr.s() have to be added by hand too.
      • [x] Changed/added classes/methods/functions have appropriate versionadded, versionchanged, or deprecated directives. Find the appropriate next version in our __init__.py file.
    • [x] Documentation in .rst files is written using semantic newlines.
    • [x] Changes (and possible deprecations) have news fragments in changelog.d.

    If you have any questions to any of the points above, just submit and ask! This checklist is here to help you, not to deter you from contributing!

  • attr.Factory is a little wordy

    attr.Factory is a little wordy

    attrs is a huge net win on an object like this:

    @attr.s
    class Point(object):
        def __init__(self, x, y, z):
            self.x = x
            self.y = y
            self.z = z
    
    import attr
    @attr.s
    class Point(object):
        x = attr.ib()
        y = attr.ib()
        z = attr.ib()
    

    but it's a lot less clear when you have something like this:

    class Cache(object):
        def __init__(self):
            self._stored = []
            self._by_name = {}
            self._by_id = {}
    

    which becomes

    @attr.s
    class Cache(object):
        _stored = attr.ib(default=attr.Factory(list))
        _by_name = attr.ib(default=attr.Factory(dict))
        _by_id = attr.ib(default=attr.Factory(dict))
    

    I think an alias for this behavior, like:

    @attr.s
    class Cache(object):
        _stored = attr.ib(new=list)
        _by_name = attr.ib(new=dict)
        _by_id = attr.ib(new=dict)
    

    could make initializing these types of mutable objects a lot less verbose.

  • attrs._make should document why it is more restrictive with __eq__ than other comparisons

    attrs._make should document why it is more restrictive with __eq__ than other comparisons

    The type check in __eq__ for generated classes is different than in other comparison methods.

    For all other methods, isinstance(other, self.__class__) is used, which means subclasses will participate in the "happy" branch of the comparison.

    For __eq__ though, other.__class__ is self.__class__ is used, so a trivial subclass will not compare equal, leading to the quite confusing:

    >>> import attr; Parent = attr.make_class("Parent", dict(foo=attr.ib())); Child = type("Child", (Parent,), {}); print (Parent(foo=1) == Parent(foo=1), Parent(foo=1) == Child(foo=1), Parent(foo=1) < Parent(foo=2), Child(foo=1) < Parent(foo=2))
    (True, False, True, True)
    

    This strikes me as a bug (the incongruity), and that __eq__ should use the same check, but even if it isn't, it likely bears mentioning that there's a difference.

    It even seems like dataclasses have even done something oddly similar, maybe just straight copying the code here?

    https://github.com/python-attrs/attrs/commit/d134ce45fc98323576a19f03e39669dce615c4e1 looks like it's the commit that originally made the change (though since then __eq__ now is hand-generated).

  • don't use __annotations__

    don't use __annotations__

    https://github.com/python-attrs/attrs/blob/aa501176fac1f12912f863fd2f5c4d1d08410322/src/attr/_make.py#L213 uses __annotations__

    However, it looks as though an upcoming incompatible change to Python will change __annotations__ into a list of strings.

    It seems like the correct public API to use to retrieve the information attrs wants would be get_type_hints.

    As a bonus, fixing this might make #265 easier to implement.

  • Validating, __init__-based assoc.

    Validating, __init__-based assoc.

    Here is an __init__-based assoc implementation that handles private attributes.

    Using the same three classes from #116, I've done benchmark runs for all-public and all-private attributes on the classes. Private attributes add a slight overhead now, the old implementation was unaffected. Underscores in front of class names indicate private attributes were used.

                    A                       B                      C
    --------------------------------------------------------------------------------------
    Old assoc:      10.6  us +- 0.3  us     12.7  us +- 0.2  us    14.8  us +- 0.3  us
    New assoc:       2.07 us +- 0.06 us      5.23 us +- 0.13 us     8.83 us +- 0.28 us
    
    
                    _A                      _B                     _C
    --------------------------------------------------------------------------------------
    Old assoc:      10.5  us +- 0.2  us     12.6  us +- 0.2 us     14.9 us +- 0.3 us
    New assoc:       2.58 us +- 0.07 us      6.16 us +- 0.12 us    10.7 us +- 0.2 us
    

    I'm pretty sure we could handle the users supplying both private and public attribute names (i.e. both setter and init syntax) with a tiny performance cost, but is it worth it? First of all,

    There should be one-- and preferably only one --obvious way to do it.

    second, could there be corner cases? I can't think of any (

    class A:
        _a = attr.ib()
       __a = attr.ib()
    

    isn't one of them, fortunately :) but maybe there are some?

    Doc change and CHANGELOG entry to come when we're satisfied with the implementation.

  • evolve() is broken if dunder attribute names are defined.

    evolve() is broken if dunder attribute names are defined.

    Basically, if @define is applied to a class def with a dunder attribute name, like __x__, then calling evolve on an instance of this class raises an exception. This is because evolve only removes the first_ leading underscore, whereas the generated __init__(self, x__=..., ...) removes all leading underscores.

    The fix is to use lstrip(name, "_") in the evolve function.

    I gather that Attribute will be getting an alias member, which evolve() will make use of, rather than doing the stripping on its own. This might fix the problem. At least if define() makes use of that feature without the class def having to use it explicitly.

    A test case could be:

    @attrs.define
    class C:
        __x__: int
        __y__: int = 42
        __z: int = 42    # mangled to _C__z.
    
    C(0).evolve()       # Should not raise an exception
    

    See #1060.

  • Ability to define class member name that is part of constructor signature but *not* an attribute

    Ability to define class member name that is part of constructor signature but *not* an attribute

    Here's a frustrating example for me.

    @define
    class C(str):
        # The second argument is not used here
        def __new__(cls, s: str, n: int): return super().__new__(cls, s)
    
        n: int
    

    How can I create a C with something like c = C('foo', 42), such that c.n == 42 and str(c) == 'foo'??

    The auto generated __init__ method has only an n parameter. Thus the above constructor call will give me an error because after calling __new__(cls, 'foo', 42) it calls __init__(self, 'foo', 42).

    I am forced to define my own __init__(self, s: str, n: int) method, which will set the self.n attribute and call any conversions and validators, as well as using object.__setattr__ if the class is frozen.

    Alternatively,

    • I can use @define(init=False) and create my own
        def __init__(self, s: str = 'bar', n: int = 0):
            self.__attrs_init__(n)
    
    • I have to take care to use the same default for n as I declared in the class; I need to use NOTHING if there is a default factory involved, so that __attrs_init__ will call the factory.

    I propose a field keyword which will mark s as only a parameter name. No suggestions as to what would be a good keyword. Thus my class would look like

    @define
    class C(str):
        # The second argument is not used here
        def __new__(cls, s: str = 'bar', n: int = 0): return super().__new__(cls, s)
    
        s: str = field(xxx = True, default='bar')
        n: int = 0
    

    The auto-generated `init' would look something like this:

        def __init__(self, s: str = 'bar', n: int = 0):
            # Run __attrs_pre_init__
            # Set self.n = n, with any conversions
            # Run validators, including any defined for `s`.
            # Run __attrs_post_init__
    

    That is, the same as would be without the field(xxx=True) but without setting self.s. I think that a conversion for s should be illegal, because the intention is for s to be a __new__ parameter, without any conversion. A validator for s should use s without any conversion.

    By the way, the order of the attributes is not important, other than mandatory attributes appearing first. So if I had a mandatory n and an optional s, I would mention n before s.

  • Add example of creating attribute within `field_transformer`

    Add example of creating attribute within `field_transformer`

    Hi, the docs state it is possible to add and transform attributes by using the field_transformer parameter to attr.s.

    I would like to create a data class like:

    def split(cls: type, attributes: typing.List[attr.Attribute]):
        for attribute in attributes:
            if attribute.name == "subnet":
                try:
                    subnet, mask = attribute.split("/")
                    subnet_attr = attribute.evolve(name="subnet", converter=lambda _: subnet)
                    mask_attr = attr.Attribute(  # type: ignore
                        name="mask", default=mask, validator=attr.validators.instance_of(int),
                        repr=True, cmp=None, hash=None, init=False, inherited=False,
                        type=int,
                    )
                    return [subnet_attr, mask_attr]
                except Exception as e:
                    print(f"Error while converting subnet {attribute}: {e}")
        return []
    
    
    @attr.s(field_transformer=split)
    class IPV4Network:
        subnet: str = attr.ib()
    

    When I try to use it I get:

    Error while converting subnet Attribute(name='subnet', default=NOTHING, validator=None, repr=True, eq=True, eq_key=None, order=True, order_key=None, hash=None, init=True, metadata=mappingproxy({}), type=<class 'str'>, converter=None, kw_only=False, inherited=False, on_setattr=None): 'Attribute' object has no attribute 'split'
    Traceback (most recent call last):
      File "a.py", line 28, in <module>
        ip = IPV4Network("42.42.42.0/24")
    TypeError: __init__() takes 1 positional argument but 2 were given
    

    It doesn' trigger an error if I use:

    import attr
    import typing
    
    
    def split(cls: type, attributes: typing.List[attr.Attribute]):
        for attribute in attributes:
            if attribute.name == "subnet":
                try:
                    subnet, mask = attribute.split("/")
                    subnet_attr = attribute.evolve(name="subnet", converter=lambda _: subnet)
                    mask_attr = attr.Attribute(  # type: ignore
                        name="mask", default=mask, validator=attr.validators.instance_of(int),
                        repr=True, cmp=None, hash=None, init=False, inherited=False,
                        type=int,
                    )
                    return [subnet_attr, mask_attr]
                except Exception as e:
                    print(f"Error while converting subnet {attribute}: {e}")
        return []
    
    
    @attr.s(field_transformer=split)
    class IPV4Network:
        subnet: str = attr.ib()
    
    
    ip = IPV4Network("42.42.42.0/24")
    print(ip)
    

    but the result is:

    IPV4Network(subnet='42.42.42.0', mask=10)
    

    Which is not what I wanted (note the mask).

    What is my mistake?

  • Q: Could I define a attr.ib in a function?

    Q: Could I define a attr.ib in a function?

    or there is another way do that?

    e. g.

    import attr
    from attrs import define, fields, field
    
    @attr.s
    class Cat:
        name = attr.ib(default='John')
    
        def do_something(self):
            name2 = attr.ib(default='Tom')
    
  • Class helper functions - Support for generic classes

    Class helper functions - Support for generic classes

    I noticed that functions like attr.has, attr.fields, attr.fields_dict doesn't work as i expected when i pass in class with generic type defined:

    
    from attr import frozen, evolve, mutable, has, fields, fields_dict, Attribute
    
    T = TypeVar("T")
    
    @frozen
    class A(Generic[T]):
        a: int
        b: T
    
    has(A) => True
    has(A[str]) => False (should be True)
    
    fields(A) => Sequence[Attribute]
    fields(A[str]) => TypeError: Passed object must be a class (should be Sequence[Attribute])
    
    fields_dict(A) => Mapping[str, Attribute]
    fields(A[str]) => TypeError: Passed object must be a class (should be Mapping[str, Attribute])```
  • Reference cycle for slot classes

    Reference cycle for slot classes

    Even the birds on the branches nowadays know we do a class switcheroo when defining slot classes.

    The initial class (the one we throw away) is part of a reference cycle with something else, so it doesn't get GC'd right away. A tiny example:

    from attrs import define
    
    
    @define
    class A:
        a: int
    
    
    @define
    class B(A):
        b: int
    
    
    # collect()
    print(A.__subclasses__())  # [<class '__main__.B'>, <class '__main__.B'>]
    

    If gc.collect() is called right afterwards, the old class gets cleaned up, so it's almost certainly a reference cycle.

    So, a good issue for someone getting started with attrs: find out what the reference cycle is and break it so this doesn't happen.

    Alternatively, we could call gc.collect() ourselves. We could also check for the old class in __subclasses__() and emit a warning if we find it there; it probably means someone is using a bare super somewhere we didn't rewrite it.

A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.
A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.

A python package containing all the basic functions and classes for python. From simple addition to advanced file encryption.

May 22, 2022
pydsinternals - A Python native library containing necessary classes, functions and structures to interact with Windows Active Directory.
pydsinternals - A Python native library containing necessary classes, functions and structures to interact with Windows Active Directory.

pydsinternals - Directory Services Internals Library A Python native library containing necessary classes, functions and structures to interact with W

Oct 14, 2022
Pyfunctools is a module that provides functions, methods and classes that help in the creation of projects in python

Pyfunctools Pyfunctools is a module that provides functions, methods and classes that help in the creation of projects in python, bringing functional

Mar 12, 2022
A simple python script to generate an iCalendar file for the university classes.
A simple python script to generate an iCalendar file for the university classes.

iCal Generator This is a simple python script to generate an iCalendar file for the university classes. Installation Clone the repository git clone ht

Sep 1, 2022
Cleaning-utils - a collection of small Python functions and classes which make cleaning pipelines shorter and easier

cleaning-utils [] [] [] cleaning-utils is a collection of small Python functions

Aug 31, 2022
Allows you to canibalize methods from classes effectively implementing trait-oriented programming

About This package enables code reuse in non-inheritance way from existing classes, effectively implementing traits-oriented programming pattern. Stor

Dec 13, 2021
A python module to update the console without flashing.
A python module to update the console without flashing.

A python module to update the console without flashing.

Nov 19, 2022
A simple tool that updates your pubspec.yaml file, of a Flutter project, without altering the structure of your file.
A simple tool that updates your pubspec.yaml file, of a Flutter project, without altering the structure of your file.

A simple tool that updates your pubspec.yaml file, of a Flutter project, without altering the structure of your file.

Dec 10, 2021
Install, run, and update apps without root and only in your home directory

Qube Apps Install, run, and update apps in the private storage of a Qube Building instrutions

Nov 18, 2022
Install, run, and update apps without root and only in your home directory

Qube Apps Install, run, and update apps in the private storage of a Qube. Build and install in Qubes Get the code: git clone https://github.com/micahf

Nov 18, 2022
✨ Voici un code en Python par moi, et en français qui permet d'exécuter du Javascript en Python.
✨ Voici un code en Python par moi, et en français qui permet d'exécuter du Javascript en Python.

JavaScript In Python ❗ Voici un code en Python par moi, et en français qui permet d'exécuter du Javascript en Python. ?? Une vidéo pour vous expliquer

Mar 28, 2022
Simple python module to get the information regarding battery in python.
Simple python module to get the information regarding battery in python.

Battery Stats A python3 module created for easily reading the current parameters of Battery in realtime. It reads battery stats from /sys/class/power_

Oct 21, 2022
ticktock is a minimalist library to view Python time performance of Python code.

ticktock is a minimalist library to view Python time performance of Python code.

Sep 28, 2022
Find dependent python scripts of a python script in a project directory.

Find dependent python scripts of a python script in a project directory.

Dec 5, 2021
A functional standard library for Python.

Toolz A set of utility functions for iterators, functions, and dictionaries. See the PyToolz documentation at https://toolz.readthedocs.io LICENSE New

Nov 29, 2022
🔩 Like builtins, but boltons. 250+ constructs, recipes, and snippets which extend (and rely on nothing but) the Python standard library. Nothing like Michael Bolton.

Boltons boltons should be builtins. Boltons is a set of over 230 BSD-licensed, pure-Python utilities in the same spirit as — and yet conspicuously mis

Dec 5, 2022
Retrying library for Python

Tenacity Tenacity is an Apache 2.0 licensed general-purpose retrying library, written in Python, to simplify the task of adding retry behavior to just

Dec 5, 2022
Simple yet flexible natural sorting in Python.

natsort Simple yet flexible natural sorting in Python. Source Code: https://github.com/SethMMorton/natsort Downloads: https://pypi.org/project/natsort

Nov 22, 2022
A Python utility belt containing simple tools, a stdlib like feel, and extra batteries. Hashing, Caching, Timing, Progress, and more made easy!
A Python utility belt containing simple tools, a stdlib like feel, and extra batteries. Hashing, Caching, Timing, Progress, and more made easy!

Ubelt is a small library of robust, tested, documented, and simple functions that extend the Python standard library. It has a flat API that all behav

Nov 21, 2022