<commit_before>from functools import cmp_to_key
from itertools import chain, groupby
import keyword
from threading import RLock
from weakref import WeakValueDictionary

global_class("java.lang.ClassNotFoundException")
global_class("java.lang.NoClassDefFoundError")
global_class("java.lang.reflect.InvocationTargetException")


cdef class_lock = RLock()
cdef dict jclass_cache = {}
cdef instance_cache = WeakValueDictionary()
# class_lock also protects none_casts in utils.pxi.

# Attributes which will never be looked up as Java members. This prevents infinite recursion, and is
# also important for performance.
cdef set special_attrs = set(dir(type) +                        # Special Python attributes
                             ["_chaquopy_j_klass",              # Chaquopy class attributes
                              "_chaquopy_reflector",            #
                              "_chaquopy_this",                 # Chaquopy instance attributes
                              "_chaquopy_real_obj",             #
                              "_chaquopy_len"])                 # Chaquopy array attributes


cpdef jclass(clsname, cls_dict=None):
    """Returns a Python class for a Java class or interface type. The name must be fully-qualified,
    using either Java notation (e.g. `java.lang.Object`) or JNI notation (e.g.
    `Ljava/lang/Object;`). To refer to a nested or inner class, separate it from the containing
    class with `$`, e.g. `java.lang.Map$Entry`.

    If the class cannot be found, a `NoClassDefFoundError` is raised.
    """
    if clsname.startswith("["):
        return jarray(clsname[1:])
    if clsname in java.primitives_by_name:
        raise ValueError("Cannot reflect a primitive type")
    if clsname.startswith("L") and clsname.endswith(";"):
        clsname = clsname[1:-1]
    clsname = clsname.replace('/', '.')

    if not isinstance(clsname, str):
        clsname = str(clsname)

    with class_lock:
        cls = jclass_cache.get(clsname)
        if cls:
            if cls_dict:
                raise ValueError("Can't alter class dict: class has already been reflected")
            return cls
        else:
            cls = new_class(clsname, None, cls_dict)
        return cls


cdef new_class(cls_name, bases, cls_dict=None):
    if cls_dict is None:
        cls_dict = {}
    cls_dict["_chaquopy_name"] = cls_name
    return JavaClass(None, bases, cls_dict)


# It might be possible to make this a cdef class, but then we wouldn't be able to use it with
# six.with_metaclass anymore.
class JavaClass(type):
    def __new__(metacls, cls_name, bases, cls_dict):
        java_name = cls_dict.pop("_chaquopy_name", None)
        if not java_name:
            raise TypeError("Java classes can only be inherited using static_proxy or dynamic_proxy")

        # _chaquopy_j_klass will already be set for a proxy class, in which case we'll leave
        # __name__ and __module__ set to the Python-level values the user would expect.
        if "_chaquopy_j_klass" not in cls_dict:
            cls_dict["_chaquopy_j_klass"] = CQPEnv().FindClass(java_name)
            if ("." in java_name) and ("[" not in java_name):
                module, _, cls_name = java_name.rpartition(".")
            else:
                module, cls_name = "", java_name
            cls_dict["__module__"] = module

        if bases is None:  # When called from jclass()
            klass = Class(instance=cls_dict["_chaquopy_j_klass"])
            bases = get_bases(klass) + cls_dict.pop("_chaquopy_post_bases", ())
            if (StaticProxy is not None) and (StaticProxy in bases):
                raise TypeError(f"static_proxy class {java_name} loaded before its Python "
                                f"counterpart")

        cls = type.__new__(metacls, cls_name, bases, cls_dict)
        cls.__qualname__ = cls.__name__  # Otherwise repr(Object) would contain "JavaObject".
        jclass_cache[java_name] = cls
        return cls

    # We do this in JavaClass.__call__ rather than JavaObject.__new__ because there's no way
    # for __new__ to prevent __init__ from being called or to modify its arguments, and
    # __init__ may be overridden by user-defined proxy classes.
    def __call__(cls, *args, JNIRef instance=None, **kwargs):
        self = None
        if instance:
            assert not (args or kwargs)
            with class_lock:
                self = instance_cache.get((cls, instance))  # Include cls in key because of cast()
                if not self:
                    env = CQPEnv()
                    if not env.IsInstanceOf(instance, cls._chaquopy_j_klass):
                        expected = sig_to_java(klass_sig(env, cls._chaquopy_j_klass))
                        actual = sig_to_java(object_sig(env, instance))
                        raise TypeError(f"cannot create {expected} proxy from {actual} instance")
                    self = cls.__new__(cls, *args, **kwargs)

                    actual_j_klass = env.GetObjectClass(instance)
                    if actual_j_klass == cls._chaquopy_j_klass:
                        real_obj = None  # Setting to `self` would cause a reference cycle with self.__dict__.
                    else:
                        real_sig = klass_sig(env, actual_j_klass)
                        real_obj = jclass(real_sig)(instance=instance)
                    set_this(self, instance.global_ref(), real_obj)
        else:
            self = type.__call__(cls, *args, **kwargs)  # May block

        return self

    def __getattribute__(cls, str name):
        if not (name in special_attrs or name in type_dict(cls)):
            reflect_member(cls, name)
        return type.__getattribute__(cls, name)

    # Override to allow static field set (type.__setattr__ would simply overwrite the class dict)
    def __setattr__(cls, str name, value):
        if not (name in special_attrs or name in type_dict(cls)):
            reflect_member(cls, name)
        member = type_lookup(cls, name)
        if isinstance(member, JavaMember):
            member.__set__(None, value)
        else:
            type.__setattr__(cls, name, value)

    # In Python 2, object.__dir__ doesn't exist (https://bugs.python.org/issue12166).
    def __dir__(cls):
        result = set()
        for c in cls.__mro__:<commit_msg>Add assertion to help diagnose https://github.com/Electron-Cash/Electron-Cash/issues/1692<commit_after>from functools import cmp_to_key
from itertools import chain, groupby
import keyword
from threading import RLock
from weakref import WeakValueDictionary

global_class("java.lang.ClassNotFoundException")
global_class("java.lang.NoClassDefFoundError")
global_class("java.lang.reflect.InvocationTargetException")


cdef class_lock = RLock()
cdef dict jclass_cache = {}
cdef instance_cache = WeakValueDictionary()
# class_lock also protects none_casts in utils.pxi.

# Attributes which will never be looked up as Java members. This prevents infinite recursion, and is
# also important for performance.
cdef set special_attrs = set(dir(type) +                        # Special Python attributes
                             ["_chaquopy_j_klass",              # Chaquopy class attributes
                              "_chaquopy_reflector",            #
                              "_chaquopy_this",                 # Chaquopy instance attributes
                              "_chaquopy_real_obj",             #
                              "_chaquopy_len"])                 # Chaquopy array attributes


cpdef jclass(clsname, cls_dict=None):
    """Returns a Python class for a Java class or interface type. The name must be fully-qualified,
    using either Java notation (e.g. `java.lang.Object`) or JNI notation (e.g.
    `Ljava/lang/Object;`). To refer to a nested or inner class, separate it from the containing
    class with `$`, e.g. `java.lang.Map$Entry`.

    If the class cannot be found, a `NoClassDefFoundError` is raised.
    """
    if clsname.startswith("["):
        return jarray(clsname[1:])
    if clsname in java.primitives_by_name:
        raise ValueError("Cannot reflect a primitive type")
    if clsname.startswith("L") and clsname.endswith(";"):
        clsname = clsname[1:-1]
    clsname = clsname.replace('/', '.')

    if not isinstance(clsname, str):
        clsname = str(clsname)

    with class_lock:
        cls = jclass_cache.get(clsname)
        if cls:
            if cls_dict:
                raise ValueError("Can't alter class dict: class has already been reflected")
            return cls
        else:
            cls = new_class(clsname, None, cls_dict)
        return cls


cdef new_class(cls_name, bases, cls_dict=None):
    if cls_dict is None:
        cls_dict = {}
    cls_dict["_chaquopy_name"] = cls_name
    return JavaClass(None, bases, cls_dict)


# It might be possible to make this a cdef class, but then we wouldn't be able to use it with
# six.with_metaclass anymore.
class JavaClass(type):
    def __new__(metacls, cls_name, bases, cls_dict):
        java_name = cls_dict.pop("_chaquopy_name", None)
        if not java_name:
            raise TypeError("Java classes can only be inherited using static_proxy or dynamic_proxy")

        # _chaquopy_j_klass will already be set for a proxy class, in which case we'll leave
        # __name__ and __module__ set to the Python-level values the user would expect.
        if "_chaquopy_j_klass" not in cls_dict:
            cls_dict["_chaquopy_j_klass"] = CQPEnv().FindClass(java_name)
            if ("." in java_name) and ("[" not in java_name):
                module, _, cls_name = java_name.rpartition(".")
            else:
                module, cls_name = "", java_name
            cls_dict["__module__"] = module

        if bases is None:  # When called from jclass()
            klass = Class(instance=cls_dict["_chaquopy_j_klass"])
            bases = get_bases(klass) + cls_dict.pop("_chaquopy_post_bases", ())
            if (StaticProxy is not None) and (StaticProxy in bases):
                raise TypeError(f"static_proxy class {java_name} loaded before its Python "
                                f"counterpart")

        cls = type.__new__(metacls, cls_name, bases, cls_dict)
        cls.__qualname__ = cls.__name__  # Otherwise repr(Object) would contain "JavaObject".
        jclass_cache[java_name] = cls
        return cls

    # We do this in JavaClass.__call__ rather than JavaObject.__new__ because there's no way
    # for __new__ to prevent __init__ from being called or to modify its arguments, and
    # __init__ may be overridden by user-defined proxy classes.
    def __call__(cls, *args, JNIRef instance=None, **kwargs):
        self = None
        if instance:
            assert not (args or kwargs)
            with class_lock:
                self = instance_cache.get((cls, instance))  # Include cls in key because of cast()
                if not self:
                    env = CQPEnv()
                    if not env.IsInstanceOf(instance, cls._chaquopy_j_klass):
                        expected = sig_to_java(klass_sig(env, cls._chaquopy_j_klass))
                        actual = sig_to_java(object_sig(env, instance))
                        raise TypeError(f"cannot create {expected} proxy from {actual} instance")
                    self = cls.__new__(cls, *args, **kwargs)

                    actual_j_klass = env.GetObjectClass(instance)
                    if actual_j_klass == cls._chaquopy_j_klass:
                        real_obj = None  # Setting to `self` would cause a reference cycle with self.__dict__.
                    else:
                        real_sig = klass_sig(env, actual_j_klass)
                        real_cls = jclass(real_sig)
                        assert actual_j_klass == real_cls._chaquopy_j_klass, (
                            # https://github.com/Electron-Cash/Electron-Cash/issues/1692
                            f"when instantiating {cls}, signature '{real_sig}' returned "
                            f"{real_cls} with j_klass {real_cls._chaquopy_j_klass}, which differs "
                            f"from instance j_klass {actual_j_klass}")
                        real_obj = real_cls(instance=instance)
                    set_this(self, instance.global_ref(), real_obj)
        else:
            self = type.__call__(cls, *args, **kwargs)  # May block

        return self

    def __getattribute__(cls, str name):
        if not (name in special_attrs or name in type_dict(cls)):
            reflect_member(cls, name)
        return type.__getattribute__(cls, name)

    # Override to allow static field set (type.__setattr__ would simply overwrite the class dict)
    def __setattr__(cls, str name, value):
        if not (name in special_attrs or name in type_dict(cls)):
            reflect_member(cls, name)
        member = type_lookup(cls, name)
        if isinstance(member, JavaMember):
            member.__set__(None, value)
        else:
            type.__setattr__(cls, name, value)

    # In Python 2, object.__dir__ doesn't exist (https://bugs.python.org/issue12166).
    def __dir__(cls):
        result = set()
        for c in cls.__mro__:
{'fraction_non_alphanumeric': 0.08411073189230185, 'fraction_numerical': 0.0019719378081152826, 'mean_word_length': 2.2286973555337903, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3305428', 'n_tokens_mistral': 3745, 'n_tokens_neox': 3733, 'n_words': 1116}