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

Multiple published documents search #29

Open
sv9388 opened this issue Apr 12, 2019 · 4 comments
Open

Multiple published documents search #29

sv9388 opened this issue Apr 12, 2019 · 4 comments

Comments

@sv9388
Copy link

sv9388 commented Apr 12, 2019

Multiple document search is supported by EPO 3.2. But I don't see an interface for the same in the code. A constructor overloading in Docdb would help achieve the same in Python3. Here is an edited version of models.py that I am using to achieve the same.

import inspect
import types

class MultiMethod:
    '''
    Represents a single multimethod.
    '''
    def __init__(self, name):
        self._methods = {}
        self.__name__ = name

    def register(self, meth):
        '''
        Register a new method as a multimethod
        '''
        sig = inspect.signature(meth)

        # Build a type-signature from the method's annotations
        types = []
        for name, parm in sig.parameters.items():
            if name == 'self': 
                continue
            if parm.annotation is inspect.Parameter.empty:
                raise TypeError(
                    'Argument {} must be annotated with a type'.format(name)
                    )
            if not isinstance(parm.annotation, type):
                raise TypeError(
                    'Argument {} annotation must be a type'.format(name)
                    )
            if parm.default is not inspect.Parameter.empty:
                self._methods[tuple(types)] = meth
            types.append(parm.annotation)

        self._methods[tuple(types)] = meth

    def __call__(self, *args):
        '''
        Call a method based on type signature of the arguments
        '''
        types = tuple(type(arg) for arg in args[1:])
        meth = self._methods.get(types, None)
        if meth:
            return meth(*args)
        else:
            raise TypeError('No matching method for types {}'.format(types))
        
    def __get__(self, instance, cls):
        '''
        Descriptor method needed to make calls work in a class
        '''
        if instance is not None:
            return types.MethodType(self, instance)
        else:
            return self
    
class MultiDict(dict):
    '''
    Special dictionary to build multimethods in a metaclass
    '''
    def __setitem__(self, key, value):
        if key in self:
            # If key already exists, it must be a multimethod or callable
            current_value = self[key]
            if isinstance(current_value, MultiMethod):
                current_value.register(value)
            else:
                mvalue = MultiMethod(key)
                mvalue.register(current_value)
                mvalue.register(value)
                super().__setitem__(key, mvalue)
        else:
            super().__setitem__(key, value)

class MultipleMeta(type):
    '''
    Metaclass that allows multiple dispatch of methods
    '''
    def __new__(cls, clsname, bases, clsdict):
        return type.__new__(cls, clsname, bases, dict(clsdict))

    @classmethod
    def __prepare__(cls, clsname, bases):
        return MultiDict()

## Actual Docdb change
class Docdb(BaseInput, metaclass=MultipleMeta):
    def __init__(self, number:str, country_code:str, kind_code:str, date:str=None):
        if not all([country_code, kind_code]):
            raise MissingRequiredValue(
                'number, country_code, and kind_code must be present'
            )
        super(Docdb, self).__init__(number, country_code, kind_code, date)

    def __init__(self, data_points:list):
        self.data_points = []
        for dp in data_points:
            d = Docdb(dp[0], dp[1], dp[2])
            self.data_points.append(d)

    def as_api_input(self):
        print(self.__dict__.keys(), )
        if hasattr(self, 'data_points'):
            print(self.data_points)
            print("#" * 20)
            return '\n'.join([x.as_api_input() for x in self.data_points])
        return super(Docdb, self).as_api_input()
@gsong
Copy link
Member

gsong commented May 30, 2019

Will you consider making a PR for this?

@sv9388
Copy link
Author

sv9388 commented Jun 10, 2019

Sure. Will do this week sometime. This interface was quite useful for some of my project. Kudos.

@amotl
Copy link
Member

amotl commented Jan 15, 2024

Dear @sv9388,

thanks for your suggestions, and a belated happy new year. Are you still using this library in one way or another, and would you be up for submitting a corresponding patch? Maintenance is boringhard, and we appreciate any support on this or other matters.

With kind regards,
Andreas.

@CholoTook
Copy link
Contributor

On the topic of maintenance, I had co-pilot draft several docstrings. Shall I submit them as a PR?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants