Custom entrypoints

From @WoLfulus on Sun Jan 14 2018 14:00:01 GMT+0000 (UTC)

I’m trying to automate some documentation on my services, and I’m struggling to get things to work. I’m new to nameko, only used it for testing and I’m feeling a little lost to get something more advanced like this to work.

Problem is that I have no idea where/how to collect class and method information to get the data I need: the closest thing I got was to write a class Documentation(Rpc) and rpc = Documentation.decorator and use that decorator instead to access the service class with self.container.service_cls, but it seems that it executes for every method, and I need to group the information up. Also I have no idea how I could access the Documentation instance inside the action later.

In resume, what I want to accomplish it:

  • Write a normal service
  • Do something really simple if needed to the service (like a dependency docs = Documentation())
  • A new rpc method “documentation” will be added automatically (without writing additional code) and it should return the docstrings from the class and its methods
  • Should be able to call n.rpc.myservice.documentation() and get the data I need

Example

How service is written

class Service:
    """a docstring"""
    name = "myservice"

    @rpc
    def test(self):
        """another docstring"""
        return True

How service will behave like

class Service:
    """a docstring"""
    name = "myservice"

    @rpc
    def test(self):
        """another docstring"""
        return True

    @rpc
    def documentation(self):
        return { 
            "service": "a doc string",
            "methods": {
                "test": "another docstring", 
            }
        }

Thoughts?

Copied from original issue: https://github.com/nameko/nameko/issues/503

From @mattbennett on Sun Jan 14 2018 15:53:39 GMT+0000 (UTC)

You can actually do this statically. I think the piece of the puzzle you’re missing is how entrypoints register themselves. It’s here:

The ENTRYPOINT_EXTENSIONS_ATTR constant is just nameko_entrypoints.

Here’s an example of static inspection:

import inspect

from nameko.rpc import rpc

class Service:
    """ A service """

    name = 'service'

    @rpc
    def method(self):
        """ A method """
        return True


def is_decorated(obj):
    return inspect.isfunction(obj) and getattr(obj, 'nameko_entrypoints', None)


entrypoint_methods = inspect.getmembers(Service, is_decorated)

print(Service.__doc__)
for name, method in entrypoint_methods:
    print(method.__doc__)

It would be easy to wrap this up into a callable entrypoint as well, of course.