Code Monkey home page Code Monkey logo

boltons's Introduction

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 missing from — the standard library, including:

Full and extensive docs are available on Read The Docs. See what's new by checking the CHANGELOG.

Boltons is tested against Python 3.7-3.12, as well as PyPy3.

Installation

Boltons can be added to a project in a few ways. There's the obvious one:

pip install boltons

On macOS, it can also be installed via MacPorts:

sudo port install py-boltons

Then, thanks to PyPI, dozens of boltons are just an import away:

from boltons.cacheutils import LRU
my_cache = LRU()

However, due to the nature of utilities, application developers might want to consider other options, including vendorization of individual modules into a project. Boltons is pure-Python and has no dependencies. If the whole project is too big, each module is independent, and can be copied directly into a project. See the Integration section of the docs for more details.

Third-party packages

The majority of boltons strive to be "good enough" for a wide range of basic uses, leaving advanced use cases to Python's myriad specialized 3rd-party libraries. In many cases the respective boltons module will describe 3rd-party alternatives worth investigating when use cases outgrow boltons. If you've found a natural "next-step" library worth mentioning, see the next section!

Gaps

Found something missing in the standard library that should be in boltons? Found something missing in boltons? First, take a moment to read the very brief architecture statement to make sure the functionality would be a good fit.

Then, if you are very motivated, submit a Pull Request. Otherwise, submit a short feature request on the Issues page, and we will figure something out.

boltons's People

Contributors

acatton avatar asottile avatar aulemahal avatar blebo avatar cameroncairns avatar coady avatar crazymerlyn avatar david-bannon avatar ekimekim avatar ericfrederich avatar erotemic avatar gliptak avatar harens avatar hugovk avatar immerrr avatar kdeldycke avatar kiwidrew avatar kurtbrose avatar mahmoud avatar markrwilliams avatar mgaitan avatar nicoddemus avatar rollcat avatar suzaku avatar thedrow avatar tirkarthi avatar tiwo avatar toddrme2178 avatar wzyboy avatar zerosteiner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

boltons's Issues

strip() that works with iterables

I'd like strip / rstrip / lstrip that works with arbitrary iterables:

def iter_lstrip(li, it): 
    pos = 0
    while li[pos] == it:
        pos += 1
        if pos == len(li):
            return []
    return li[pos:]


def iter_rstrip(li, it):
    return list(reversed(iter_lstrip(list(reversed(li)), it)))


def iter_strip(li, it):
    return iter_lstrip(iter_rstrip(li, it), it)
iter_strip([0,0,0,1,2,3,4,0,0], 0)
# [1,2,3,4]

Link to the docs?

Hey! This library seems awesome. It'd be nice if you linked directly to the docs in the README so folks won't have to guess where to learn about the libraries. Thanks!

Clarification of project allegance

While the boltons project laudably disavows upfront any association with Michael Bolton, it is nonetheless silent on the matter of whether or not it has anything to do with Ramsay Bolton – which I would argue is a more pressingly pertinent disclosure.

ramsay-bolton-face-sadistic-typical

If at all possible, an explicit note in README.md about whether or not this project is at all related to Ramsay Bolton, one way or the other, would no doubt be appreciated by any and all users of this otherwise robust and circumspectly complete Python utility package. Thank you!

`LRU` fails after `max_size` insertions

Hi,
here's an example:

from boltons.cacheutils import LRU
cache = LRU(max_size = 2)
for i in xrange(4):
    cache[i] = i
    print(cache)
LRU(max_size=None, on_miss=2, values={0: 0})
LRU(max_size=None, on_miss=2, values={0: 0, 1: 1})
LRU(max_size=None, on_miss=2, values={1: 1, 2: 2})
Traceback (most recent call last):
  File "test_lru.py", line 9, in <module>
    cache[i] = i
  File "/usr/local/lib/python2.7/dist-packages/boltons/cacheutils.py", line 140, in __setitem__
    del self.link_map[oldkey]
KeyError: None

Add lookahead to iterutils

Would it be possible to add lookahead generator to boltons.iterutils:

import six

def lookahead(iterable):
    it = iter(iterable)
    last = six.next(it)
    for val in it:
        yield last, False
        last = val
    yield last, True

I can make a PR with tests and docs if you're ok with this.

What happened with six as dependency btw.? I see it was added in #11 but is no longer in master?

tbutils ExceptionInfo and TracebackInfo to_dict() result not JSON serializable

I wanted to use tbutils to serialize whatever exceptions thrown at me and store them in a DB but to_dict() result is not JSON serializable which is kind of weird.

When I looked it up it seems that it's because line field in each CallPoint object is not of a native str type (although it says it is in the docs). It is of type boltons.tbutils._DeferredLine.

I wrote a JSON serializer that handles that, but if there is no special reason for that I suggest returning a native string. Or at least update the documentation.

remap convert set to set of tuples

bolton's remap convert sets to sets of tuples, where first element of tuple is index in set, second is value.

In [1]: !pip show boltons

---
Metadata-Version: 2.0
Name: boltons
Version: 16.5.0
...

In [2]: from boltons.iterutils import remap, default_enter

In [3]: def enter(path, key, value):
   ...:     ret = default_enter(path, key, value)
   ...:     return ret
   ...:

In [4]: d = {"set": {1, 2, 3}}

In [5]: remap(d, enter=enter)
Out[5]: {'set': {(0, 1), (1, 2), (2, 3)}}

Python 3.5.1 (v3.5.1:37a07cee5969, Dec 6 2015, 01:54:25) [MSC v.1900 64 bit (AMD64)]
Windows 7

Adding entry to LRU cache fails with KeyError

For certain sequences of key insertions, a KeyError is produced in the LRU

For example:

def produce_key_error():
    from boltons.cacheutils import LRU
    cache = LRU(max_size=3)

    keys = ['A', 'A', 'B', 'A', 'C', 'B', 'D', 'E']
    for k in keys:
        cache[k] = 'HIT'

Make it possible to reconstruct parsed tracebacks?

The current ParsedException class isn't compatible with "traceback" module:

[15:25:23]>>> traceback.print_tb(tb)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.7/traceback.py", line 61, in print_tb
    f = tb.tb_frame
AttributeError: 'ParsedException' object has no attribute 'tb_frame'

Perhaps it would be a good idea to make it possible to recontruct tracebacks back to strings after manipulation?

Add possibility to use cacheutils's decorator on class methods

Hi, great module first of all!
Right now I have to use cachetools module, which provides cachedmethod decorator for using with class/instance methods.

Would it be possible to implement same for cached decorator so it would be possible to run something like:

class Example(object):
    def __init__(self):
        self._cache = LRU()

    @cached(operator.attrgetter('_cache'))
    def heavy_func(self):
        print('Called')
        return 100500

instance = Example()
for _ in range(20):
    instance.heavy_func()  # should print `Called` just once

Ideally I would prefer single decorator for generic functions and for class methods, but if it's not possible it could be implemented with two different ones.

Python 3.5 support

Hey,

thanks for very useful package :)

Have you considered Python 3.5 support? Should I expect some unpredicted behaviour?

Best #regards,
Dominik Szmaj

cacheutils.LRU.on_miss behavior

Hi Guys,

spot_cache = cacheutils.LRU(max_size=20000, on_miss=get_spot)

When I try to access the cache with

spot_cache.get('some-cache-key')
  • if such key doesn't exist - get_spot func will be fired, that will connect to underlying stack (like DB etc) to select the value. Let's say such key doesn't exist in the database and get_spot returns None.

The problem is that that key/None combination is being cached increasing memory and evicting other good keys from the cache.

How to approach a solution that only positive values are cached through on_miss callable?

thanks,
Dmitry

Function to split path

Would something like this be acceptable?

    def split_all(path):
        all_parts = []
        while True:
            parts = os.path.split(path)
            if parts[0] == path:  # sentinel for absolute paths
                all_parts.insert(0, parts[0])
                break
            elif parts[1] == path:  # sentinel for relative paths
                all_parts.insert(0, parts[1])
                break
            else:
                path = parts[0]
                all_parts.insert(0, parts[1])
        return all_parts

Insert line of text into exception

One thing I often need to do is to insert an additional line of text into the exception message when handling an exception. My main use-case for is in loops, particularly in unit tests, where I want to insert additional context information (such as the loop index) to make it easier to track down the source of the exception.

I also considered the idea of being able to alter the existing message, but I concluded that this is bad programming practice, hence the proposal to only append.

So something like this:

for i, item in enumerate(mylist):
    try:
        myfunc(item)
    except BaseException:
        AppendMsg('Exception for item %s: %s' % (i, item))
        raise

I would be willing to implement this myself, but I want to verify that it would be acceptable before working on it.

Add a PriorityQueue that works with unhashable items?

I want to store unhashable things in a priority queue. For example,

from boltons.queueutils import PriorityQueue
q = PriorityQueue()
for i in range(10):
    q.add(dict(a=i), 0)

But that produces TypeError: unhashable type: 'dict'.

heapq won't work either, because if I store tuples (-priority, item), I can get comparisons between dicts if priorities match.

Right now I'm using this instead:

from boltons.listutils import BList
from bisect import insort

class Heap():
    def __init__(self):
        self._q = BList()
        self._items = {}
        self._idx = 0

    def add(self, item, priority):
        idx = self._idx
        self._idx += 1
        insort(self._q, (-priority, idx))
        self._items[idx] = item

    def pop(self):
        priority, idx = self._q.pop(0)
        return self._items.pop(idx)

    def __len__(self):
        return len(self._q)

    def __iter__(self):
        while self._q:
            yield self.pop()

Add flatten function?

One of the most commonly requested list/iterable-wrangling functions is a recipe to flatten an arbitrarily nested sequence of sequences (or of iterables). This seems like the sort of thing that would be a good fit for boltons, perhaps in iterutils. Some implementations:

socketutils failures on Windows

Another follow-on from #71

The tests\test_socketutils.py file has 9 failures on Windows python 2.7 and 3.4, and 2 failures on Windows python 3.5.

python 2.7: https://ci.appveyor.com/project/conda-forge/staged-recipes/build/1.0.2072/job/8e0vidh6my09nlrt
python 3.4: https://ci.appveyor.com/project/conda-forge/staged-recipes/build/1.0.2072/job/4tw9568trk76v9mp
python 3.5: https://ci.appveyor.com/project/conda-forge/staged-recipes/build/1.0.2072/job/uy77xdh8x8qlwgxg

Again, I'll dig in on a PR at some point if somebody else doesn't beat me to it.

Plural of index

In strutils, the plural of index should be either indexes or indicies, but not indeces.

Functions to work with json structures

I've recently build a few functions to work with nested structures coming from a JSON web API.

data = {"ID1":{"result":{"name":"Jan Schulz"}},
        "ID2":{"result": {"name":"Another name", "bday":"1.1.2000"}}}
print(find_in_structure(data, "Schulz"), get_from_structure(data, find_in_dict(data, "Schulz")))
## ID1.result.name Jan Schulz
converter_dict = dict(
    names = "result.name",
    bday = "result.bday"
)
import pandas as pd
print(pd.DataFrame(convert_to_dataframe_input(data, converter_dict)))
##   _index      bday         names
## 0    ID1       NaN    Jan Schulz
## 1    ID2  1.1.2000  Another name

I just found this lib and these three functions seem to fit in with boltons.iterutils.remap and boltons.jsonutils. Would you be willing to take them in?

Code is currently here: http://janschulz.github.io/working_with_dicts.html

Thread pool

So I have a small thread pool library. I've noticed that the existing python thread pool implementations are not well maintained and/or have insufficient documentation.

Would merging this with boltons be entertained?

Thanks,
Sriram

ParsedException.from_string produces wrong result when a frame is missing source (such as from eval)

Take this (modified from the original) trace:

Traceback (most recent call last):
  File "<string>", line 2, in _some_function
  File "myfile.py", line 3, in some_other_function
    return foo(bar, baz)
MyException: ExceptionValue

ParsedException gives me an incorrect result:

>>> ParsedException.from_string(x)
ParsedException(u'    return foo(bar, baz)', u'', frames=[{'source_line': u'File "myfile.py", line 3, in some_other_function', 'filepath': u'<string>', 'lineno': u'2', 'funcname': u'_some_function'}])

PermissionError with AtomicSaver on Windows

If I try this little code on Windows 7:

from boltons.fileutils import AtomicSaver
with AtomicSaver('foo.txt') as f:
    f.write('whatever')

I get the following Exception:

Traceback (most recent call last):
  File "C:\Python34\lib\site-packages\boltons\fileutils.py", line 272, in setup
    overwrite=self.overwrite_part)
  File "C:\Python34\lib\site-packages\boltons\fileutils.py", line 194, in _atomic_rename
    os.rename(path, new_path)
PermissionError: [WinError 32] Der Prozess kann nicht auf die Datei zugreifen, da sie von einem ande
ren Prozess verwendet wird: 'C:\\Windows\\System32\\tmphia0tzzm' -> 'foo.txt.part'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python34\lib\site-packages\boltons\fileutils.py", line 281, in __enter__
    self.setup()
  File "C:\Python34\lib\site-packages\boltons\fileutils.py", line 274, in setup
    os.unlink(tmp_part_path)
PermissionError: [WinError 32] Der Prozess kann nicht auf die Datei zugreifen, da sie von einem ande
ren Prozess verwendet wird: 'C:\\Windows\\System32\\tmphia0tzzm'

funcutils.wraps() with injected keyword does not work for keyword-only arguments.

Given the following decorator:

def inject_loop(func):
      sig = inspect.signature(func)
      loop_param = sig.parameters['loop'].replace(default=None)
      sig = sig.replace(parameters=[loop_param])

      def add_loop(
          args: typing.Tuple[typing.Any, ...],
          kwargs: typing.Dict[str, typing.Any]
      ) -> collections.OrderedDict:
          bargs = sig.bind(*args, **kwargs)
          bargs.apply_defaults()
          if bargs.arguments['loop'] is None:
              bargs.arguments['loop'] = asyncio.get_event_loop()

          return bargs.arguments

      if inspect.isasyncgenfunction(func):
          async def async_gen_loop_wrapper(*args, **kwargs):
              async for elem in func(**add_loop(args, kwargs)):
>>                yield elem
          ret = async_gen_loop_wrapper

      elif inspect.iscoroutinefunction(func):
          async def async_loop_wrapper(*args, **kwargs):
              return await func(**add_loop(args, kwargs))
          ret = async_loop_wrapper

      elif inspect.isgeneratorfunction(func):
          def gen_loop_wrapper(*args, **kwargs):
              yield from func(**add_loop(args, kwargs))
          ret = gen_loop_wrapper

      else:
          def func_loop_wrapper(*args, **kwargs):
              return func(**add_loop(args, kwargs))
          ret = func_loop_wrapper

      return boltons.funcutils.wraps(func, injected=['loop'])(ret)

The following code fails:

@inject_loop
def example(*, loop):  # loop is a keyword-only argument
    return loop

with the following stacktrace:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
.../python3.6/site-packages/boltons/funcutils.py in remove_arg(self, arg_name)
    565         try:
--> 566             self.args.remove(arg_name)
    567         except ValueError:

ValueError: list.remove(x): x not in list

During handling of the above exception, another exception occurred:

MissingArgument                           Traceback (most recent call last)
<ipython-input-3-6ef3f4f5dc19> in <module>()
----> 1 @lib.inject_loop
      2 def example(*, loop):
      3     return loop

... in inject_loop(func)
    169         ret = func_loop_wrapper
    170
--> 171     return boltons.funcutils.wraps(func, injected=['loop'])(ret)
    172
    173

.../python3.6/site-packages/boltons/funcutils.py in wraps(func, injected, **kw)
    295     for arg in injected:
    296         try:
--> 297             fb.remove_arg(arg)
    298         except MissingArgument:
    299             if inject_to_varkw and fb.varkw is not None:

.../python3.6/site-packages/boltons/funcutils.py in remove_arg(self, arg_name)
    569                                   % (arg_name, self.name, self.args))
    570             exc.arg_name = arg_name
--> 571             raise exc
    572         d_dict.pop(arg_name, None)
    573         self.defaults = tuple([d_dict[a] for a in self.args if a in d_dict])

MissingArgument: arg 'loop' not found in example argument list: []

However, it works if I do this:

@inject_loop
def example(loop):  # Not a keyword-only argument
    return loop

I believe the solution should also check the kwonly args when attempting to mark a parameter as "injected", so that keyword only arguments can be listed in the injected parameter to wraps().

remerge - dictionaries with arrays as values fail (slightly)

I forked your gist to https://gist.github.com/pleasantone/c99671172d95c3c18ed90dc5435ddd57.
The fork fundamentally adds no new code, other than extremely verbose debugging prints to
simply record the problem without anyone needing to single-step through with a debugger.

The significant change in the code is the addition of 'zones': [{'a': 1}], to overlay.

which produces

{0: {'a': 1},
 'endpoints': {'cache': {'host': '127.0.0.2', 'port': 8889},
               'persistence': {'host': '10.2.2.2', 'port': 5433}},
 'host': '127.0.0.1',
 'overlay_version': '5.0',
 'port': 8080,
 'zones': <Recursion on dict with id=140392218983688>}

The output gets interesting right here:

path=(), key=zones, value=[{'a': 1}]
new_parent=[], new_items=<enumerate object at 0x7faf9c57e0d8>
updating new_parent to ret={'host': '127.0.0.1', 'endpoints': {'cache': {'host': '127.0.0.1', 'port': 8889}, 'persistence': {'host': '127.0.0.1', 'port': 8888}}, 'port': 8000}
KeyError
returning new_parent={'host': '127.0.0.1', 'endpoints': {'cache': {'host': '127.0.0.1', 'port': 8889}, 'persistence': {'host': '127.0.0.1', 'port': 8888}}, 'port': 8000}, new_items=<enumerate object at 0x7faf9c57e0d8>
path=('zones',), key=0, value={'a': 1}
new_parent={}, new_items=ItemsView({'a': 1})
KeyError
returning new_parent={}, new_items=ItemsView({'a': 1})
path=('zones', 0), key=a, value=1
new_parent=1, new_items=False
KeyError
returning new_parent=1, new_items=False

new_parent should not be {}

`LRU` thread safety fails after `max_size` insertions

Hi, i've come across an error when using LRU in a multi-threaded app, heres an example:

from boltons.cacheutils import LRU
import threading
import time

cache = LRU(max_size = 2)

def fill_cache():
    for i in xrange(5):
        cache[i] = i
        print(cache)
        time.sleep(0.1)

t1 = threading.Thread(target=fill_cache)
t2 = threading.Thread(target=fill_cache)

t1.start()
t2.start()

t1.join()
t2.join()
LRU(max_size=2, on_miss=None, values={0: 0})
LRU(max_size=2, on_miss=None, values={0: 0})
LRU(max_size=2, on_miss=None, values={0: 0, 1: 1})
LRU(max_size=2, on_miss=None, values={1: 1})
LRU(max_size=2, on_miss=None, values={1: 1, 2: 2})
Exception in thread Thread-1:
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "lrutest.py", line 9, in fill_cache
    cache[i] = i
  File "/Users/mauri/.virtualenvs/lrutest/lib/python2.7/site-packages/boltons/cacheutils.py", line 149, in __setitem__
    del self.link_map[oldkey]
KeyError: 0

LRU(max_size=2, on_miss=None, values={2: 2, 3: 3})
Exception in thread Thread-2:
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File "lrutest.py", line 9, in fill_cache
    cache[i] = i
  File "/Users/mauri/.virtualenvs/lrutest/lib/python2.7/site-packages/boltons/cacheutils.py", line 149, in __setitem__
    del self.link_map[oldkey]
KeyError: 1

In case it helps, im using python 2.7.10 and boltons 15.1.0

ps: Thanks for an awesome library!

Make it possible to use single cache for different methods

Would it be possible to implement cache separation of different methods with same signature for cachedmethod decorator? Here is small example with use of boltons and cachetools:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import operator
from boltons import cacheutils
import cachetools


class BoltonsCalculator(object):
    def __init__(self):
        self.cache = cacheutils.LRU()

    @cacheutils.cachedmethod('cache')
    def square(self, number):
        print("Calculating square of {}".format(number))
        return number * number

    @cacheutils.cachedmethod('cache')
    def cube(self, number):
        print("Calculating cube of {}".format(number))
        return number * number * number


class CachetoolsCalculator(object):
    def __init__(self):
        self.cache = cachetools.LRUCache(128)

    @cachetools.cachedmethod(operator.attrgetter('cache'))
    def square(self, number):
        print("Calculating square of {}".format(number))
        return number * number

    @cachetools.cachedmethod(operator.attrgetter('cache'))
    def cube(self, number):
        print("Calculating cube of {}".format(number))
        return number * number * number


if __name__ == '__main__':
    boltons_calc = BoltonsCalculator()
    print(boltons_calc.square(2))
    print(boltons_calc.square(2))
    print(boltons_calc.cube(2))

    print('-' * 80)

    cachetools_calc = CachetoolsCalculator()
    print(cachetools_calc.square(2))
    print(cachetools_calc.square(2))
    print(cachetools_calc.cube(2))

Here is output:

Calculating square of 2
4
4
4 <== I expect to get 8 here
--------------------------------------------------------------------------------
Calculating square of 2
4
4
Calculating cube of 2
8

Process finished with exit code 0

As you can see, third print gives us 4, though I expect to get 8.
Maybe this could help you better understand how this is implemented in cachetools.

`cached` not returning function

Hi,

great collections of utilities! Unless I misunderstand something though, the cached decorator is missing a return (and a unit test). As is, it returns None, rendering it useless... Creating the CachedFunction directly works as intended...

Thx for sharing your code!

`LRU.__repr__` bug

Hi,

Thanks for fixing cached, now it works great. I've been playing with LRU and there's another small problem:

def __repr__(self):
        cn = self.__class__.__name__
        val_map = super(LRU, self).__repr__()
        return ('%s(max_size=%r, on_miss=%r, values=%s)'
                % (cn, self.on_miss, self.max_size, val_map))

has max_size and on_miss reversed.

'cachedproperty' decorator replace original's method docstring

I'm using cachedproperty a lot as a decorator but the latter seems to replace the original method's docstring by its own.

See for instance that code: https://github.com/kdeldycke/maildir-deduplicate/blob/v2.0.1/maildir_deduplicate/mail.py#L59-L68 . It is rendered by Sphinx with the decorator's docstring instead of the one from the decorated method. See: https://maildir-deduplicate.readthedocs.io/en/stable/maildir_deduplicate.html#maildir_deduplicate.mail.Mail.message

Add "one" function

I have a tiny package called one with just one "missing" function " to check if there is a unique value that evaluates to True in an iterable".

https://github.com/mgaitan/one

I propose to merge it in the boltons's iterutils module. I can send a PR if you like it

socketutils error in master on OSX

I'm working on building conda packages for boltons through conda-forge. The in-progress PR is conda-forge/staged-recipes#560

Linux packages build just fine (and it looks like those are what's covered in your .travis.yml). There is one error on OS X and a few on Windows. I'll file the Windows ticket separately.

The OS X error is in tests/test_socketutils.py:test_client_disconnecting and the full error output is here

__________________________ test_client_disconnecting ___________________________
    def test_client_disconnecting():
        def get_bs_pair():
            x, y = socket.socketpair()
            bx, by = BufferedSocket(x), BufferedSocket(y)

            # sanity check
            by.sendall(b'123')
            bx.recv_size(3) == b'123'

            return bx, by

        bx, by = get_bs_pair()
        assert bx.fileno() > 0

        bx.close()
        assert bx.getrecvbuffer() == b''

        try:
            bx.recv(1)
        except socket.error:
            pass
        else:
            assert False, 'expected socket.error on closed recv'

        assert bx.fileno() == -1

        by.buffer(b'123')
        assert by.getsendbuffer()
        try:
            by.flush()
        except socket.error:
            assert by.getsendbuffer() == b'123'
        else:
            assert False, 'expected socket.error broken pipe'

>       by.shutdown(socket.SHUT_RDWR)
../work/tests/test_socketutils.py:137: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
self = <boltons.socketutils.BufferedSocket object at 0x102d1bd10>, how = 2
    def shutdown(self, how):
        """Convenience method which passes through to the wrapped socket's
            :meth:`~socket.shutdown`. Semantics vary by platform, so no
            special internal handling is done with the buffers. This
            method exists to facilitate the most common usage, wherein a
            full ``shutdown`` is followed by a
            :meth:`~BufferedSocket.close`. Developers requiring more
            support, please open `an issue`_.

            .. _an issue: https://github.com/mahmoud/boltons/issues
            """
        with self._recv_lock:
            with self._send_lock:
>               self.sock.shutdown(how)
E               error: [Errno 57] Socket is not connected
../work/boltons/socketutils.py:559: error

Wanted to file the issue to start. At some point I'll dig in on a PR if somebody else doesn't get to it first.

Cached property

I'm currently using cached-property alongside boltons and I feel like cached-property features can be emulated with boltons.cacheutils.

Is this under the scope of boltons? Should we add some utils to support this feature in boltons?

Return a pair from boltons.iterutils.bucketize

EDIT: nevermind, just read the docs for partition. Derp

Hey there,

Reading the docs of this lib and wondering why not return a pair from bucketize?

Current behavior:

>>> bucketize(range(5))
{False: [0], True: [1, 2, 3, 4]}
>>> is_odd = lambda x: x % 2 == 1
>>> bucketize(range(5), is_odd)
{False: [0, 2, 4], True: [1, 3]}

Instead:

>>> bucketize(range(5))
{False: [0], True: [1, 2, 3, 4]}
>>> is_odd = lambda x: x % 2 == 1
>>> bucketize(range(5), is_odd)
([0, 2, 4], [1, 3])

I feel this will make client code more straightforward.

>>> groups = bucektize(range(5), is_odd)
>>> even_nums = groups[False]
>>> odd_nums = groups[True]

vs.

>>> even_nums, odd_nums = bucketize(range(5), is_odd)

Thoughts?

`boltons.funcutils.wraps` breaks with Python 3 function annotations

Tested with boltons==17.1.0

Repro: Executing the following script fails

from boltons.funcutils import wraps
from typing import Optional

def wrap_it(f):
    @wraps(f)
    def wrapper(self, *args, **kwargs):
        f(*args, **kwargs)
    return wrapper

@wrap_it
def foo(x: Optional[int]) -> Optional[int]:
    return x

Results in

rwilliams at rwilliams-mbp114 in ~/src/oss/boltons (master●) (venv)
$ python ../../test_wraps_with_annotations.py
Traceback (most recent call last):
  File "../../test_wraps_with_annotations.py", line 11, in <module>
    def foo(x: Optional[int]) -> Optional[int]:
  File "../../test_wraps_with_annotations.py", line 5, in wrap_it
    @wraps(f)
  File "/Users/rwilliams/src/oss/boltons/boltons/funcutils.py", line 307, in wrapper_wrapper
    fully_wrapped = fb.get_func(execdict, with_dict=update_dict)
  File "/Users/rwilliams/src/oss/boltons/boltons/funcutils.py", line 526, in get_func
    self._compile(src, execdict)
  File "/Users/rwilliams/src/oss/boltons/boltons/funcutils.py", line 590, in _compile
    exec(code, execdict)
  File "<boltons.funcutils.FunctionBuilder-0>", line 1, in <module>
NameError: name 'Union' is not defined

fileutils error on Windows

A follow-on from #71

python 2.7, 3.4, and 3.5--both 32-bit and 64-bit--have a test failure in the fileutils.

_________________ [doctest] boltons.fileutils.iter_find_files _________________
462             search. Yielded paths will include this as a prefix. 
463         patterns (str or list): A single pattern or list of 
464             glob-formatted patterns to find under *directory*. 
465         ignored (str or list): A single pattern or list of 
466             glob-formatted patterns to ignore.
467  
468     For example, finding Python files in the current directory: 
469  
470     >>> filenames = sorted(iter_find_files(_CUR_DIR, '*.py')) 
471     >>> filenames[-1].split('/')[-1] 
Expected:
    'typeutils.py'
Got:
    'C:\\Miniconda-x64\\conda-bld\\work\\boltons\\typeutils.py' 

C:\Miniconda-x64\conda-bld\work\boltons\fileutils.py:471: DocTestFailure 

Looks like a simple fix to use os.path.basename there instead of .split('/').

I'll work on a PR at some point if somebody else doesn't beat me to it.

remap enter to skip some items

During iteration through data I would like to skip some items.
As described in docs, it should be possible to skip visiting some elements if return False as a second value from return. But even with such a trivial example I've got an error:

remap({'foo': 'bar'}, enter=lambda p, k, v: ({}, False))
>>> TypeError: expected remappable root, not: {'foo': 'bar'}

Am I doing something wrong or it's a bug?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.