How to make Class instance in main.py available in another file? - python

I am having difficulty where I need to make the information available in a class that is instantiated in main.py in another file. The best way to describe what I am trying to do can be seen in the flow diagram below:
The issue as you can imagine is with circular dependency. Is there a way to create an interface between schema.py and main.py so that I can pass class information?
Thank you for your time and any help you can offer!
EDIT: Added code for reference
ws_transport.py
from autobahn.twisted.websocket import (
WebSocketServerProtocol,
WebSocketServerFactory,
)
from schema import schema
class WsProtocol(WebSocketServerProtocol):
def __init__(self):
# Code here
def onConnect(self, request):
# Code here
def onMessage(self, payload, isBinary):
# Code here
class WsProtocolFactory(WebSocketServerFactory):
def __init__(self):
super(WsProtocolFactory, self).__init__()
self.connection_subscriptions = defaultdict(set)
# Code here
def check_events_db(self):
# Code here
def check_audit_log_db(self):
# Code here
web_transport.py
import sys, os
import json
from twisted.web.resource import Resource
from twisted.web.server import Site, http
from schema import schema
class HttpResource(Resource):
isLeaf = True
def render_OPTIONS(self, request):
# Code here
def render_GET(self, request):
# Code here
def render_POST(self, request):
# Code here
class LoginResource(Resource):
isLeaf = True
def render_OPTIONS(self, request):
# Code here
def render_GET(self, request):
# Code here
def render_POST(self, request):
# Code here
class RefreshResource(Resource):
isLeaf = True
def render_OPTIONS(self, request):
# Code here
def render_GET(self, request):
# Code here
def render_POST(self, request):
# Code here
class HttpFactory(Site):
def __init__(self, resource):
# Code here
schema.py
#!/usr/bin/python
import graphene
import json
import sys, os
from main import factory
class Query(graphene.ObjectType):
# Code here
class Mutation(graphene.ObjectType):
# Code here
class Subscription(graphene.ObjectType):
# Code here
schema = graphene.Schema(query=Query, mutation=Mutation, subscription=Subscription)
main.py
import sys
from twisted.internet import reactor
from twisted.web.resource import Resource
from autobahn.twisted.resource import WebSocketResource
from ws_transport import WsProtocol, WsProtocolFactory
from web_transport import HttpResource, LoginResource, RefreshResource, HttpFactory
if __name__ == '__main__':
factory = WsProtocolFactory()
factory.protocol = WsProtocol
ws_resource = WebSocketResource(factory)
root = Resource()
root.putChild("", HttpResource())
root.putChild("login", LoginResource())
root.putChild("refresh", RefreshResource())
root.putChild(b"ws", ws_resource)
site = HttpFactory(root)
reactor.listenTCP(8000, site)
reactor.run()
Cheers,
Brian

I know this is not necessarily the answer you need. But I ran into the same problem and for me it meant that I have structured the project wrong. Meaning main.py or schema.py do things they are not meant to do. Of course you made the project so you get to decide what does what but what I mean is that maybe you should abstract even more. Since I do not quite understand what you want to do with the code since I do not know the libraries.
A simple hacky sort of thing is to just create another file called maybe run.py that then imports both files and dependency-injects main into schema or the other way around.
Another not-so-nice solution is to create an init() function that then imports the other file after the rest has been initialized and therefore insures that the import is only executed once.
But what I did was to check conceptually why main needed to import (in your case) schema and then ask myself is this really what main.py is supposed to do. If e.g. your main needs to provide templates to all other modules then why not create a templates.py or modules.py? Or what in my case was better is to create a bus system. This could allow modules to share only the data needed when needed and exposes a general api. But of course this would only make sense if you only share information.
In conclusion: Usually when the application is well designed you never run into circular imports. When you do it is a sign that you should rethink about how you structure your program.

For Python functions you could do something like this.
def functionInSchema(objectParameter):
# Add in code
This will give you access to the object from the main.py file.
To access attributes/methods use the parameter name, a dot and the attribute/function name.
def functionInSchema(objectParameter):
attribute = objectParameter.attribute
objectParameter.method()
Then in main.py you pass the Class instance (Object) as a parameter.
objectInMain = Class(param1, param2)
functionInSchema(objectInMain)
If you need access to the class in schema.py you can use the following import.
from main.py import ClassName
I hope this helped you! Good luck!

Related

In Django Factory Boy, is it possible to mute a specific receiver (not all signals)?

In our Django project, we have a receiver function for post_save signals sent by the User model:
#receiver(post_save, sender=User)
def update_intercom_attributes(sender, instance, **kwargs):
# if the user is not yet in the app, do not attempt to setup/update their Intercom profile.
if instance.using_app:
intercom.update_intercom_attributes(instance)
This receiver calls an external API, and we'd like to disable it when generating test fixtures with factory_boy. As far as I can tell from https://factoryboy.readthedocs.io/en/latest/orms.html#disabling-signals, however, all one can do is mute all post_save signals, not a specific receiver.
At the moment, the way we are going about this is by defining an IntercomMixin which every test case inherits from (in the first position in the inheritance chain):
from unittest.mock import patch
class IntercomMixin:
#classmethod
def setUpClass(cls):
cls.patcher = patch('lucy_web.lib.intercom.update_intercom_attributes')
cls.intercomMock = cls.patcher.start()
super().setUpClass()
#classmethod
def tearDownClass(cls):
super().tearDownClass()
cls.patcher.stop()
However, it is cumbersome and repetitive to add this mixin to every test case, and ideally, we'd like to build this patching functionality into the test factories themselves.
Is there any way to do this in Factory Boy? (I had a look at the source code (https://github.com/FactoryBoy/factory_boy/blob/2d735767b7f3e1f9adfc3f14c28eeef7acbf6e5a/factory/django.py#L256) and it seems like the __enter__ method is setting signal.receivers = []; perhaps this could be modified so that it accepts a receiver function and pops it out of the the signal.receivers list)?
For anyone looking for just this thing and finding themselves on this question you can find the solution here: https://stackoverflow.com/a/26490827/1108593
Basically... call #factory.django.mute_signals(post_save) on the test method itself; or in my case the setUpTestData method.
Test:
# test_models.py
from django.test import TestCase
from django.db.models.signals import post_save
from .factories import ProfileFactory
import factory
class ProfileTest(TestCase):
#classmethod
#factory.django.mute_signals(post_save)
def setUpTestData(cls):
ProfileFactory(id=1) # This won't trigger user creation.
...
Profile Factory:
#factories.py
import factory
from factory.django import DjangoModelFactory
from profiles.models import Profile
from authentication.tests.factories import UserFactory
class ProfileFactory(DjangoModelFactory):
class Meta:
model = Profile
user = factory.SubFactory(UserFactory)
This allows your factories to keep working as expected and the tests to manipulate them as needed to test what they need.
In case you want to mute all signals of a type, you can configure that on your factory directly. For example:
from django.db.models.signals import post_save
#factory.django.mute_signals(post_save)
class UserFactory(DjangoModelFactory):
...

Django Testing - loading data into the database before loading the apps

I'm currently writting some tests for a Django app (+ REST framework), and having some issues loading the test data into the database.
Let me explain with some (very simplified) code :
I have a django view which is something like :
view.py
from myapp.models import Item
from myapp.utils import MyClass
# need to initialize with the set of items
item_set = {item.name for item in Item.objects.all()}
my_class_object = MyClass(item_set)
class MyView(APIView):
def post(selfself, request):
result = my_class_object.process(request.data)
return Response(result)
So basically I need to initialize a class with some data from the database, and I then use this class in my view to process the data received by the endpoint.
Now the test :
my_test.py
from rest_framework.test import APILiveServerTestCase
from myapp.models import Item
class MyTest(APILiveServerTestCase):
def setUp(self):
self.URL = '/some_url_linking_to_myview/'
# load some data
Item.objects.create(name="first item")
Item.objects.create(name="second item")
def test_myview_return_correct_result(self):
post_data = {"foo"}
response = self.client.post(self.URL,
data=post_data,
format='json')
self.assertEqual(response.status_code, 200)
self.assertEqual(response.data, {"my_expected_result"})
When running the test, what currently happens is that view.py is loaded before the setUp() method get excecuted, so when I instantiate the class with these two lines :
item_set = {item.name for item in Item.objects.all()}
my_class_object = MyClass(item_set)
the database is still empty.
I'm wondering if there is a way to either get the data into the database before view.py get executed, or maybe somehow force reloading the app after setUp(), or instantiate my class somewhere else so it gets called after loading the data ?
thanks !
I think you are looking for setUpTestData().
Here is roughly how I set this up if I am going to use a significant amount of data:
tests.py
from django.test import TestCase
from .tests.test_data import base_data
class MyClassTest(TestCase):
#classmethod
def setUpTestData(cls):
base_data.base_data(cls)
base_data.py
from .models import MyClass
def base_data(cls):
cls.MyClass1 = MyClass.objects.create(
name="first_name"
)
cls.MyClass2 = MyClass.objects.create(
name="second_name"
)
Of course, you can do everything directly in the setUpTestData() function, if you would rather have your test data sitting up top.
Why not put the initiate code in the function and call from inside the post.
class MyView(APIView):
def initialize(self):
item_set = {item.name for item in Item.objects.all()}
my_class_object = MyClass(item_set)
def post(self, request):
self.initialize()
result = my_class_object.process(request.data)
return Response(result)
Edit 1
Optionally, you can use fixture to load MyClass objects in the database beforehand
class MyTest(APILiveServerTestCase):
fixtures = [
// my class objects fixtures file
]
def setUp():
// rest of the code

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):

Django UnitTest with Mock

I am writing an Unit-Test for a Django class-based view.
class ExampleView(ListView):
def get_context_data(self, **kwargs):
context = super(EampleView, self).get_context_data(**kwargs)
## do something else
def get_queryset(self, **kwargs):
return self.get_data()
def get_data(self):
call_external_API()
## do something else
The key issue is that call_external_API() in get_data().
When I am writing Unit-test, I don't really want to call external API to get data. First, that will cost my money; second, I can easily test that API in another test file.
I also can easily test this get_data() method by having an unit-test only for it and mock the output of call_external_API().
However, when I test this whole class-based view, I simply will do
self.client.get('/example/url/')
and check the status code and context data to verify it.
In this case, how do I mock this call_external_API() when I am testing the whole class-based view?
What your are looking for is patch from unittest.mock. You can patch call_external_api() by a MagicMock() object.
Maybe you want to patch call_external_api() for all your tests in class. patch give to you essentialy two way to do it
decorate the test class
use start() and stop() in setUp() and tearDown() respectively
Decorate a class by patch decorator is like decorate all test methods (see documentation for details) and the implementation will be very neat. Follow example assume that your view is in my_view module.
#patch("my_view.call_external_api", autospec=True)
class MyTest(unittest.TestCase):
def setUp(self):
self.client = Client()
def test_get_data(self, mock_call_external_api):
self.client.get('/example/url/')
self.assertTrue(mock_call_external_api.called)
More sophisticate examples can be build and you can check how you call mock_call_external_api and set return value or side effects for your API.
I don't give any example about start and stop way to do it (I don't really like it) but I would like to spend some time on two details:
I assumed that in your my_view module you define call_external_api or you import it by from my_API_module import call_external_api otherwise you should pay some attention on Where to patch
I used autospec=True: IMHO it should be used in every patch call and documentation explain why very well
You can mock the call_external_api() method when testing the classed based view with something like this:
import modulea
import unittest
from mock import Mock
class ExampleTestCase(unittest.TestCase):
def setUp(self):
self.call_external_api = modulea.call_external_api
def tearDown(self):
modulea.call_external_api = self.call_external_api
def get_data(self):
modulea.call_external_api = Mock(return_value="foobar")
modulea.call_external_api()
## do something else

How to structure re-used code between modules

I'm pretty new to Python and, in writing an app, have ended up with a structure that's a bit of a mess. The example below should illustrate what I'm trying to do. The issue is that I can't call the login method from common.py because it is only defined in website1.py or website2.py.
Module common.py
class Browser():
def load_page():
Login.login()
Module website1.py
import common.py
class Login:
#staticmethod
def login():
#code to login to this website 1
Module website2.py
import common.py
#staticmethod
class Login:
def login():
#code to login to website 2
Any thoughts on how to restructure this would be appreciated.
First of all, why static methods? You could just do def login at the global level.
Second of all, you could pass a class reference to the Browser class. (or a module reference if you take my first suggestion)
class Browser(object):
def __init__(self, loginCls):
self.loginCls = loginCls
def login_page(self):
self.loginCls.login()

Categories