Coder Social home page Coder Social logo

rounder's People

Contributors

nyggus avatar salabim avatar

Stargazers

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

Watchers

 avatar  avatar

rounder's Issues

Improve type hints

IntOrFloat is totally unnecessary, as int is consistent with float so can be used wherever float can be used.

Create `signif` function

Create signif function - move its implementation from Rounder to this function, and then offer signif and signif_object.

Check Python 3.12

In addition, add setuptools to the dev dependencies. (Python 3.12 does not come with the built-in installation.)

signif has wrong type hint

The type hint for x in signif is IntOrFloat, where that should be Number.
Also, the return type is also Number.

Change names of functions

To avoid overlapping with math and built-in names, change function names to round_object() and so on.

Optimize performance

In order to optimize the performance, it would be better to avoid too many tests in a sequence. Therefore, I do a kind of hierarchical test now.
Note that I also replace lookups like Numbers.number and collections.Mapping by globals as that saves time.
To avoid a test and to make the product more stable. I am now capturing exceptions and if one is raised, I simply return unconverted.

By far not as elegant as the previous version, but it certainly will perform better.

Here it is:

import array
import builtins
import copy
import math
import numbers
from collections.abc import Sequence
from collections.abc import Container
from collections.abc import Set
from collections.abc import Mapping
from collections import deque
from numbers import Number

class UnpickableObjectError(Exception):
    pass


class NonNumericTypeError(Exception):
    pass


class NonCallableError(Exception):
    pass


def _do(func, obj, digits, use_copy):
    def convert(obj):
        try:
            if isinstance(obj, Container):            
                if isinstance(obj, Sequence):        
                    if isinstance(obj, list):
                        obj[:] = list(map(convert, obj))
                        return obj
                    if isinstance(obj, tuple):
                        if hasattr(obj, "_fields"):
                            # it's a collections.namedtuple or a typing.NamedTuple
                            return obj._replace(**convert(obj._asdict()))
                        return tuple(convert(list(obj)))
                    if isinstance(obj, deque):
                        for i, elem in enumerate(obj):
                            obj[i] = convert(elem)
                        return obj                
                if isinstance(obj, Set):
                    return type(obj)(convert(list(obj)))
                if isinstance(obj, Mapping):
                    for k, v in obj.items():
                        obj[k] = convert(obj[k])
                    return obj
                if isinstance(obj, array.array):
                    obj[:] = array.array(obj.typecode, convert(obj.tolist()))
                    return obj
            if isinstance(obj, Number):
                if isinstance(obj, complex):
                    return convert(obj.real) + convert(obj.imag) * 1j            
                return func(obj, *digits)
            if isinstance(obj, tuple):
                # it's a namedtuple
                return obj._replace(**convert(obj._asdict()))
            # try as a class instance
            convert(obj.__dict__)
            return obj

        except Exception:
            pass
        return obj

    if use_copy:
        try:
            obj = copy.deepcopy(obj)
        except TypeError:
            raise UnpickableObjectError()
    return convert(obj)

Change handling of dict

I would prefer the following code to convert a dict (more compact, no explicit loops):

    if isinstance(value, dict):
        value.update({k, convert(v)})
        return value

Make rounder work with deque, Counter, defaultdict, UserDict and UserList

I have implemented dedicated handlng for collections.deque objects.
In order for collections.Counter to work, I have changed the code for dict handling.
And I have verified that collections.defaultdict, collections.UserDict and collections.UserList work as expected.

Here's the updated code (including the support dor namedtuples):

def convert(obj):
    if isinstance(obj, complex):
        # this has to be checked before the Number check,
        # as complex is a Number
        return convert(obj.real) + convert(obj.imag) * 1j
    if isinstance(obj, numbers.Number):
        return func(obj, *digits)
    if isinstance(obj, list):
        obj[:] = list(map(convert, obj))
        return obj
    if isinstance(obj, tuple):
        if hasattr(obj, "_fields"):  # it's a namedtuple
            return obj._replace(**convert(obj._asdict()))
        else:
            return tuple(convert(list(obj)))
    if isinstance(obj, set):
        return set(convert(list(obj)))
    if isinstance(obj, frozenset):
        return frozenset(convert(list(obj)))
    if isinstance(obj, (dict, collections.OrderedDict)):
        for k, v in obj.items():
            obj[k] = convert(obj[k])
        return obj
    if isinstance(obj, array.array):
        obj[:] = array.array(obj.typecode, convert(obj.tolist()))
        return obj
    if isinstance(obj, collections.deque):
        for i, elem in enumerate(obj):
            obj[i] = convert(elem)
        return obj
    if hasattr(obj, "__dict__"):
        convert(obj.__dict__)
        return obj

    return obj

Add handling of `collections.namedtuple` and `typing.NamedTuple`

Currently a TypeError is returned when rounder objects are fed in with instances of these two types:

TypeError: __new__() missing 1 required positional argument: ...

Checking for both can be done as

isinstance(my_named_tuple, tuple) and hasattr(my_named_tuple, "_fields")

Add class instances to update attributes

It would be nice if we could also change the attributes of a class instance.
This extra code (at the bottom of convert) should do:

    if hasattr(value, "__dict__"):
        convert(value.__dict__)
        return value

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.