How to use the 'self' param inside Spyne server methods - python

I've seen in many Spyne examples that all the methods don't have the typical self parameter; there aren't examples of Spyne using the self parameter, nor cls. They use a ctx parameter, but ctx doesn't refer to the instance nor to the class (and I need to maintain some state).
Is it possible to use it? Or are the classes not instantiated, and used as static classes?
I was trying to do something similar to:
# -*- coding: utf-8 -*-
from __future__ import (
absolute_import,
unicode_literals,
print_function,
division
)
from spyne.decorator import rpc
from spyne.service import ServiceBase
from spyne.model.primitive import String
class RadianteRPC(ServiceBase):
def __init__(self, name):
self._name = name
#rpc(_returns=String)
def whoami(self):
"""
Dummy test method.
"""
return "Hello I am " + self._name + "!"
The problem with this piece of code is that RadianteRPC never seems to be instantiated as an object by Spyne, but used as a static class.
Solution 1:
As it stands, Spyne doesn't instantiate any object. Then, if we need to store some state, we can do it through class properties.
Since we can't access to the cls parameter in our methods, we need to refer the class by its name, so we can do something like:
class RadianteRPC(ServiceBase):
_name = "Example"
#rpc(_returns=String)
def whoami(ctx): # ctx is the 'context' parameter used by Spyne
"""
Dummy test method.
"""
return "Hello I am " + RadianteRPC._name + "!"
Solution 2 (found in Spyne mailing lists) :
In many cases, it's possible that we can't directly refer to the class name, so we have another alternative: find the class through the ctx parameter.
class RadianteRPC(ServiceBase):
_name = "Example"
#rpc(_returns=String)
def whoami(ctx): # ctx is the 'context' parameter used by Spyne
"""
Dummy test method.
"""
return "Hello I am " + ctx.descriptor.service_class._name + "!"

What I did is to subclass the Application class, and then access the application object through ctx.app.
from spyne.protocol.soap.soap11 import Soap11
from spyne.server.wsgi import WsgiApplication
from spyne import Application, rpc, ServiceBase, Unicode, Boolean
class MyApplication(Application):
def __init__(self, *args, **kargs):
Application.__init__(self, *args, **kargs)
assert not hasattr(self, 'session')
self.session = 1
def increment_session(self):
self.session += 1
def get_session(self):
return self.session
class Service(ServiceBase):
#rpc(_returns=Integer)
def increment_session(ctx):
s = ctx.app.get_session()
self.increment_session()
return s
application = MyApplication([MatlabAdapterService],
'spyne.soap',
in_protocol=Soap11(validator='lxml'),
out_protocol=Soap11())
wsgi_application = WsgiApplication(application)
...
I guess there should be a "cleaner" way - not requiring subclassing of the Application class - by subclassing the Context, but this should allow you to work dynamically.
To come back to your question, you also have the opportunity to access your service, since this is defined in the Application.services attribute.

Related

Is there a way to get the class Name from where I create an instance of another class by importing it?

Given:
Module A.py
class utilities:
def __init__(self):
#Is there a way to get the class that instantiates this constructor ? But here, in the init method?
def utilMethod(self):
pass
Module B.py
from A import utilities
class dummy:
utils = utilities()
def dummyMthod(self):
utils.utilMethod()
#Is there a way to get the class that instantiates utilities class constructor ? But in the init method of the class being instanciated?
Since you're instantiating utils as a static variable, at the time of its creation class dummy is not yet available so the answer is "no": you can't do that.
Alternative solution: "pass yourself in" (see code comments for explanations)
class utilities:
def __init__(self):
pass
def utilMethod(self, obj): # the caller is passed in
print(obj.__class__.__name__) # this is how we can access the class-name of the caller
pass
class dummy:
utils = utilities()
def dummyMthod(self):
self.utils.utilMethod(self) # here we "pass ourselves in"
d = dummy()
d.dummyMthod() # prints "dummy"
UPDATE
If we want to declare utils as an object attribute (vs. static class attribute in the previous snippet), we can do:
class utilities:
def __init__(self, obj):
print(obj.__class__.__name__)
pass
def utilMethod(self, obj):
pass
class dummy:
def __init__(self):
self.utils = utilities(self) # declare utils as object attribute inside the constructor and pass 'self' into utilities
def dummyMthod(self):
self.utils.utilMethod()
d = dummy() # prints "dummy"
Within __init__ (and generally within the methods of the class) you can use self.__class__ and/or self.__class__.__name__; the latter can be particularly useful for logging and similar messages.
self.logger = logging.getLogger(self.__class__.__name__)
(Or similar, perhaps also incorporating the module name.)

Get decorated class from its name in the decorator?

I decorated some methods with #bot_thinking, which stores some information about the decorated method in the functions attribute.
One piece of information is 'class_name', but my program needs the class type as a variable, e.g. RandomBot. I would like to get this class.
Here is some sample code:
class DepthPrunedMinimaxAgent(Agent):
#bot_thinking(associated_name="minimax profondeur")
def select_move(self, game_state: GameState):
Above is the decorated part of the code.
The decorator:
functions = {}
def bot_thinking(associated_name, active=True):
def _(func):
if active:
class_name = func.__qualname__.rsplit('.')[-2]
import sys
# class_name_2=getattr(sys.modules[__name__], class_name)
# module=importlib.import_module('sources.agent')
functions[associated_name] = (associated_name, class_name,
globals()[class_name], func)
else:
functions.pop(associated_name)
return _
bot_thinking isn't a real decorator, it's a decorator factory.
From the func function, I get the class_name, but I can't use the accepted answer by #m.kocikowski, to find the correct class because this class is decorated, so it already imports the annotation module, so importing from the module of the annotation the annotated module would result in a cyclic import, which python does not seem to permit.
Do you see a method to get the class from its name?
ps:
ps:
to be clearer : the annotation part of the code need an import to the annotated classes(to retrieve the class from its name), which also need an importation of the annotation (for the annotation to work).
You can do what you want if you use a descriptor class, rather than a function, as the decorator, at least if you're using Python 3.6 or newer. That's because there's a new method added to the descriptor protocol, __set_name__. It gets called when the descriptor object is saved as a class variable. While most descriptors will use it to record the name they're being saved as, you can use it to get the class you're in.
You do need to make your decorator object wrap the real function (implementing calling and descriptor lookup methods), rather than being able to return the unmodified function you were decorating. Here's my attempt at a quick and dirty implementation. I don't really understand what you're doing with functions, so I may not have put the right data in it, but it should be close enough to get the idea across (owner is the class the method stored in).
functions = {}
def bot_thinking(associated_name, active=True):
class decorator:
def __init__(self, func):
self.func = func
def __set_name__(self, owner, name):
if active:
functions[associated_name] = (associated_name, owner.__name__,
owner, self.func)
else:
functions.pop(associated_name)
def __get__(self, obj, owner):
return self.func.__get__(obj, owner)
def __call__(self, *args, **kwargs):
return self.func(*args, **kwargs)
return decorator
The problem is the class hasn't been defined yet when the bot_thinking() decorator factory (and decorator itself) are executing. The only workaround I can think of would be to patch things up after the class is defined, as illustrated below:
from pprint import pprint, pformat
functions = {}
def bot_thinking(associated_name, active=True):
def _(func):
if active:
class_name = func.__qualname__.split(".")[-2]
functions[associated_name] = (associated_name, class_name, class_name, func)
else:
functions.pop(associated_name, None)
return func # Decorators must return a callable.
return _
class Agent: pass
class GameState: pass
class DepthPrunedMinimaxAgent(Agent):
#bot_thinking(associated_name="minimax profondeur")
def select_move(self, game_state: GameState):
pass
# After class is defined, update data put into functions dictionary.
for associated_name, info in functions.items():
functions[associated_name] = (info[0], info[1], globals()[info[2]], info[3])
pprint(functions)
Output:
{'minimax profondeur': ('minimax profondeur',
'DepthPrunedMinimaxAgent',
<class '__main__.DepthPrunedMinimaxAgent'>,
<function DepthPrunedMinimaxAgent.select_move at 0x00F158A0>)}

How can I mock an object instantiated in the constructor?

I'm writing unit-tests with Pytest. I want to unit-test a class that has on its __init__ method an object that connects to a database:
data_model.py
from my_pkg.data_base_wrapper import DataBaseWrapper
class DataModel:
def __init__(self):
self.db = DataBaseWrapper()
self.db.update_data()
def foo(self):
data = self.db.get_some_data()
# make some processing and return a result
data_base_wrapper.py
class DataBaseWrapper:
def __init__(self):
# Init process of the wrapper
pass
def update_data(self):
# Connect to the database and perform some operations
pass
I've tried using monkeypatch on the DataBaseWrapper object of DataModel:
from my_pkg.data_model import DataModel
class MockDataBaseWrapper:
#staticmethod
def update_cache():
pass
#staticmethod
def get_table(table):
# Return some data for testing
pass
#pytest.fixture
def data_model(monkeypatch):
monkeypatch.setattr(DataModel, 'db', MockDataBaseWrapper)
data_model = DataModel()
return data_model
However, I get the following error:
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f10221669e8>
#pytest.fixture
def data_model(monkeypatch):
> monkeypatch.setattr(DataModel, 'db', MockDataBaseWrapper)
E AttributeError: <class 'dashboard.datamodel.DataModel'> has no attribute 'db'
I've read in the answers of similar questions, that I could try writing a sub-class of my DataBaseWrapper and change it on the DataModel class, but I'm in the same situation, as I cannot monkeypatch the attribute of the __init__ method. I can, though, if it is not in the __init__ method.
How can I write tests for this composition of classes? Suggestions on how to rewrite these classes or a different patter are also welcome.
The problem is that your MockDataBaseWrapper is totally unrelated to the DataBaseWrapper used in DataModel.
My proposal is to get rid of your MockDataBaseWrapper and:
If you want to keep your current structure, you can use patch to mock the DataBaseWrapper that is actually imported in data_model.py.
from mock import patch
from my_pkg.data_model import DataModel
def test_data_model():
with patch("my_pkg.data_model.DataBaseWrapper") as MockedDB:
mocked_db = MockedDB()
data_model = DataModel()
assert data_model.db is mocked_db
The patch context manager will replace the DataBaseWrapper class that gets imported in your data_model.py with a Mock instance and let you interact with that mock, which allows me here to verify that it got instantiated.
Note that it is very important to patch the class in the module where it is imported (and not in the model where it is defined, i.e we patch your_package.data_model.DataBaseWrapper and not your_package.data_base_wrapper.DataBaseWrapper)
If you don't mind changing your class, then the usual pattern is to inject the db parameter into the constructor of DataModel. Mocking it then becomes a piece of cake.
class DataModel:
def __init__(self, db):
self.db = db
self.db.update_data()
from mock import patch, Mock
from my_pkg.data_model import DataModel
def test_data_model():
mocked_db = Mock()
data_model = DataModel(mocked_db)
assert data_model.db is mocked_db

Calling a class method from another class causes metaclass conflict

I have a Python web app and I want to define a general class or function for processing web pages and call it from a more specific class for specific page instances.
Error:
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
I have checked all the StackOverflow questions & answers about that error message and did not understand the explanations given (and I found an article about metaclasses that I didn't understand - OOP is not really my thing). I also looked at all the StackOverflow questions & answers about calling a class method from another class (and didn't understand them either).
Code:
import webapp2
from datetime import datetime, timedelta
from google.appengine.ext import ndb
from google.appengine.api import users
import admin_templates
import authenticate
class myPage(webapp2.RequestHandler):
def get(pageInstance):
pageInstance.outputHtml()
def outputHtml(pageInstance,pageTitle,pageContent):
adminLink = authenticate.get_adminlink()
authMessage = authenticate.get_authmessage()
adminNav = authenticate.get_adminnav()
pageInstance.response.headers['Content-Type'] = 'text/html'
html = admin_templates.base
html = html.replace('#title#', pageTitle)
html = html.replace('#authmessage#', authMessage)
html = html.replace('#adminlink#', adminLink)
html = html.replace('#adminnav#', adminNav)
html = html.replace('#content#', pageContent)
pageInstance.response.out.write(html)
pageInstance.response.out.write(admin_templates.footer)
class AuditorsPage(webapp2.RequestHandler, myPage.outputHtml):
def get(self):
self.output_auditors()
def output_auditors(self):
self.outputHtml(admin_templates.auditors_title, admin_templates.auditors_content)
How do I call the outputHtml method in the myPage class from the AuditorsPage class without getting a metaclass error?
The error comes from the fact that you are subclassing your class from a method in the general class, which can't be done. Actually, your code is wrong, and there are at least two ways you can fix it:
1) Inherit from myPage instead: in this case, it won't work and will bring a MRO error because your methods are not part of any instance of the class, as they are not linked to the object using self as the first parameter.
This is the fix for your code in this case:
from google.appengine.ext import ndb
from google.appengine.api import users
import admin_templates
import authenticate
class myPage(webapp2.RequestHandler):
def get(self, pageInstance):
pageInstance.outputHtml()
def outputHtml(self, pageInstance,pageTitle,pageContent):
adminLink = authenticate.get_adminlink()
authMessage = authenticate.get_authmessage()
adminNav = authenticate.get_adminnav()
pageInstance.response.headers['Content-Type'] = 'text/html'
html = admin_templates.base
html = html.replace('#title#', pageTitle)
html = html.replace('#authmessage#', authMessage)
html = html.replace('#adminlink#', adminLink)
html = html.replace('#adminnav#', adminNav)
html = html.replace('#content#', pageContent)
pageInstance.response.out.write(html)
pageInstance.response.out.write(admin_templates.footer)
class AuditorsPage(myPage):
def get(self):
self.output_auditors()
2) Just get the two methods in the myPage class as normal methods with no class, and then call them directly from your class. Actually, you just need to create outputHtml() method, and then call it directly (without self.) from the method in your RequestHandler subclass.
Try this:
myPage.outputHtml()
instead of:
self.outputHtml()
Class AuditorsPage could inherit from myPage
import webapp2
from datetime import datetime, timedelta
from google.appengine.ext import ndb
from google.appengine.api import users
import admin_templates
import authenticate
class myPage(webapp2.RequestHandler):
def get(pageInstance):
pageInstance.outputHtml()
def outputHtml(pageInstance,pageTitle,pageContent):
adminLink = authenticate.get_adminlink()
authMessage = authenticate.get_authmessage()
adminNav = authenticate.get_adminnav()
pageInstance.response.headers['Content-Type'] = 'text/html'
html = admin_templates.base
html = html.replace('#title#', pageTitle)
html = html.replace('#authmessage#', authMessage)
html = html.replace('#adminlink#', adminLink)
html = html.replace('#adminnav#', adminNav)
html = html.replace('#content#', pageContent)
pageInstance.response.out.write(html)
pageInstance.response.out.write(admin_templates.footer)
class AuditorsPage(myPage):
def get(self):
self.output_auditors()
Then you can instanciate AuditorsPage() and call directly outputHtml
foo = AuditorsPage()
foo.outputHtml(admin_templates.auditors_title, admin_templates.auditors_content)
Ok so you are not calling super for the AuditorsPage:
class myPage():
def __init__(self):
pass
def outputHtml(self):
print("outputHTML")
class AuditorsPage(myPage):
def __init__(self):
super().__init__()
def output(self):
print("AuditorsPage")
I am using a very stripped down version of what you have to explain what is going on. As you can see, we have your myClass class. When creating an object from AuditorsPage, we are now able to access the method outputHTML as expected. Hope this helps.
Base on your question, I guess you want to inherit methods from myPage. If that is the case, instead of:
class AuditorsPage(webapp2.RequestHandler, myPage.outputHtml):
Try:
class AuditorsPage(webapp2.RequestHandler, myPage):

Bind some arbitrary value to route in Flask

How can I elegantly bind some arbitrary value and flask route? Suppose, I want to access this value in my session interface implementation or in before_request hook.
Now I'm doing it in such way:
#app.route('/foo/<bar>', defaults={'_my_val': True}):
def foo(bar, _my_val): # this is ugly hack
pass
And access this value through request object like this:
class MyRequest(flask.Request):
def get_my_val(self):
return (self.url_rule.defaults or {}).get('_my_val', False)
But it looks like a hack.
UPD: Looks like it can be done by extending werkzeug.routing.Rule class and adding **kwargs to its constructor. Is it ok to override Rule class in flask?
Eventually I ended up overriding flask's Request and Rule classes:
# here app is a Flask current application object
from flask import Request as FlaskRequest
from werkzeug.routing import Rule as FlaskRule
class Request(FlaskRequest):
def is_foo(self):
return bool(self.url_rule._foo) if self.url_rule else False
def get_bar(self):
return getattr(self.url_rule, '_bar')
class Rule(FlaskRule):
def __init__(self, *args, **kwargs):
for param in ('_foo', '_bar'):
setattr(self, param, kwargs.pop(param, None))
super().__init__(*args, **kwargs)
# app initialization
app.request_class = Request
app.url_rule_class = Rule
# route example
#app.route('/path', _foo=True, _bar='baz')
def route():
pass

Categories