Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don’t import numpy #966

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open

Don’t import numpy #966

wants to merge 21 commits into from

Conversation

hoxbro
Copy link
Member

@hoxbro hoxbro commented Aug 31, 2024

The changes made in this PR are not to directly import non-essential imports (numpy in param) but to only check for the case when the user has already imported them.

This comes down to two things:

  1. For param, this is to "hide" numpy imports in functions or generators. This is strictly not necessary, but people check import time with python -X importtime -c 'import param', and because we do an actual import of numpy, we are heavily penalized by it. The random modules (numpy and stdlib) also seem unnecessary to import, only to use the import for not outputting anything with pprint.

  2. The second part involves using a new decorator, which overloads isinstance and issubclass and still makes it function like a generator with and without calling it. This approach can be used in our other libraries, e.g., HoloViews. Here, we currently import pandas to set up different class selectors, which heavily penalizes the import time. We currently require pandas, but that may not always be the case.

Copy link

codecov bot commented Aug 31, 2024

Codecov Report

Attention: Patch coverage is 92.85714% with 4 lines in your changes missing coverage. Please review.

Project coverage is 86.55%. Comparing base (0d191dc) to head (0e273cf).

Files with missing lines Patch % Lines
param/_utils.py 87.50% 2 Missing ⚠️
param/parameterized.py 96.29% 1 Missing ⚠️
param/parameters.py 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #966      +/-   ##
==========================================
+ Coverage   86.45%   86.55%   +0.09%     
==========================================
  Files          10       10              
  Lines        5177     5199      +22     
==========================================
+ Hits         4476     4500      +24     
+ Misses        701      699       -2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@hoxbro hoxbro marked this pull request as ready for review August 31, 2024 15:37
param/parameters.py Outdated Show resolved Hide resolved
@hoxbro hoxbro marked this pull request as draft September 27, 2024 05:22
param/parameterized.py Outdated Show resolved Hide resolved
param/_utils.py Outdated
@@ -612,3 +612,15 @@ def async_executor(func):
task.add_done_callback(_running_tasks.discard)
else:
event_loop.run_until_complete(func())


def anyinstance(obj, class_tuple_generator):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could an approach like this be used to avoid creating these functions? https://peps.python.org/pep-3119/#overloading-isinstance-and-issubclass

Copy link
Member Author

@hoxbro hoxbro Sep 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, though I haven't read the PEP in detail.

However, it seems pretty advanced to use for a simple conversion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems it'd be something like:

import sys

class GeneratorIsMeta(type):
    def __instancecheck__(cls, inst):
        return isinstance(inst, tuple(cls.gen_types()))

    def __subclasscheck__(cls, sub):
        return issubclass(sub, tuple(cls.gen_types()))


class DtTypes(metaclass=GeneratorIsMeta):
    @classmethod
    def gen_types(cls):
        yield dt.datetime
        yield dt.date
        if "numpy" in sys.modules:
            import numpy as np
            yield np.datetime64

class IntTypes(metaclass=GeneratorIsMeta):
    @classmethod
    def gen_types(cls):
        yield int
        if "numpy" in sys.modules:
            import numpy as np
            yield np.integer

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you.

I still thinks it is pretty advanced (even though you don't need it to be iterable in your example).

You could likely move the advanced logic into a decorator, but then you would need to import that into our other libraries. My main point with accepting iterator is not so much for param itself but for HoloViews.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My main point with accepting iterator is not so much for param itself but for HoloViews.

Oh yeah I agree users shouldn't have to pass this custom class, a generator seems appropriate. Instead I was wondering if there couldn't be a way to use the metaclass approach internally to avoid the special anyisinstance and anyissubclass functions, they seem to be easy to forget in the future.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have switched to a metaclass approach with a decorator for easy access.

param/parameters.py Outdated Show resolved Hide resolved
@hoxbro hoxbro marked this pull request as ready for review November 9, 2024 09:13
@hoxbro hoxbro changed the title Add option for using generators for instance check Don’t import numpy Nov 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants