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

Add option for using generators for instance check #966

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
Draft

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 generators in class_ for the ClassSelector for item_type for the List. This is more related to downstream libraries, e.g., HoloViews. Here, we need to 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.

The use of generators is mainly to distinguish it from classes when passing it into the functions anysubclass and anyinstance (names are up for debate.)


To Do:

  • Add unit test for generators in class selector.

Copy link

codecov bot commented Aug 31, 2024

Codecov Report

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

Project coverage is 86.53%. Comparing base (e54dd51) to head (5b8f25f).

Files with missing lines Patch % Lines
param/parameters.py 86.66% 2 Missing ⚠️
param/_utils.py 87.50% 1 Missing ⚠️
param/parameterized.py 96.42% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #966      +/-   ##
==========================================
+ Coverage   86.45%   86.53%   +0.08%     
==========================================
  Files          10       10              
  Lines        5176     5193      +17     
==========================================
+ Hits         4475     4494      +19     
+ 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
@@ -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.

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