I need to use a function from a class in a different class(different file) and am having issues, not sure how to accomplish this and am struggling with trying to find the right help for what i'm looking for(i may be using the wrong terms).
Directory Structure:
--app
--static
--js
--templates
--main_page.html
--__init__.py
-- MainApp.py
--settings.py
server.py
server.py:
from gevent import monkey
from socketio.server import SocketIOServer
from app import app
monkey.patch_all()
listen_address = '0.0.0.0'
listen_port = 5000
print 'Starting Server on: http://{0}:{1}'.format(listen_address, listen_port)
SocketIOServer((listen_address, listen_port), app, resource="socket.io").serve_forever()
app > init.py
from flask import Flask
from flask import render_template
from flask import request
from socketio import socketio_manage
import settings
from celery import Celery
from redis import Redis
import subprocess
import requests
from socketio.namespace import BaseNamespace
def make_celery(app):
celery = Celery(app.import_name, broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
app = Flask(__name__)
app.debug = True
app.config.from_object(settings)
celery = make_celery(app)
r_server = Redis('localhost')
#app.route('/socket.io/<path:remaining>')
def socket(remaining):
socketio_manage(request.environ, {'/testclass': TestClass}, request)
return 'done'
#app.route('/')
def main_page():
return render_template('main_page.html')
class TestClass(BaseNamespace):
def on_submit(self, data):
#start mainapp
import MainApp
MainApp.MainApp()
#celery.task(name='tasks.emitter')
def emitter(self, string):
# emit to receive function in javascript... javascript pulls the 'mytext' field which contains (string)
self.emit('receive', {'mytext': string})
from socketio.namespace import BaseNamespace
import MainApp
MainApp.py
import app
class MainApp(app.TestClass):
def __init__(self):
self.emitter(self, 'test1234')
How can i use self.emit from TestClass in Mainapp? The emitter function runs self.emit that sends a string the the javascript code using websockets... I keep getting errors such as the following ...
TypeError: emitter() takes exactly 2 arguments (1 given)
OR in the case of the above...
Traceback (most recent call last):
File "/.../.../.../lib/python2.7/site-packages/gevent/greenlet.py", line 327, in run
result = self._run(*self.args, **self.kwargs)
File "/.../.../.../lib/python2.7/site-packages/socketio/virtsocket.py", line 403, in _receiver_loop
retval = pkt_ns.process_packet(pkt)
File "/.../.../.../lib/python2.7/site-packages/socketio/namespace.py", line 155, in process_packet
return self.process_event(packet)
File "/.../.../.../lib/python2.7/site-packages/socketio/namespace.py", line 225, in process_event
return self.call_method_with_acl(method_name, packet, *args)
File "/.../.../.../lib/python2.7/site-packages/socketio/namespace.py", line 240, in call_method_with_acl
return self.call_method(method_name, packet, *args)
File "/.../.../.../lib/python2.7/site-packages/socketio/namespace.py", line 282, in call_method
return method(*args)
File "/.../.../.../.../app/__init__.py", line 50, in on_submit
MainApp.MainApp()
File "/.../.../.../.../app/MainApp.py", line 11, in __init__
self.emitter(self, 'test1234')
File "/.../.../.../lib/python2.7/site-packages/celery/local.py", line 167, in <lambda>
__call__ = lambda x, *a, **kw: x._get_current_object()(*a, **kw)
File "/.../.../.../.../app/__init__.py", line 24, in __call__
return TaskBase.__call__(self, *args, **kwargs)
File "/.../.../.../lib/python2.7/site-packages/celery/app/task.py", line 420, in __call__
return self.run(*args, **kwargs)
File "/.../.../.../.../app/__init__.py", line 55, in emitter
self.emit('receive', {'mytext': string})
File "/.../.../.../lib/python2.7/site-packages/socketio/namespace.py", line 451, in emit
endpoint=self.ns_name)
AttributeError: 'MainApp' object has no attribute 'ns_name'
<Greenlet at 0x1120ad0f0: <bound method Socket._receiver_loop of <socketio.virtsocket.Socket object at 0x111c7c5d0>>> failed with AttributeError
Thanks!
I'd recommend that you explicitly create an instance of classA so avoid confusion.
class MainApp(object):
def __init__(self,emitter):
self.objA = ClassA()
self.emitter = self.objA.emitter
self.emitter('string')
You could also make it a class method, or a separate function if it needs shared:
#classmethod
#celery.task(name='tasks.emitter')
def emitter(cls, string):
cls.emit('receive', {'mytext': string})
class MainApp(object):
def __init__(self,emitter):
self.emitter = ClassA.emitter
self.emitter('string')
There is no issue here with it being in another class. Your MainApp class inherits from TestClass, so you are perfectly correct to refer to the method via self.emitter.
The only problem is that you are passing self twice: any method call, whether inherited or not, automatically passes the self argument, so you just need to pass the other argument:
self.emitter('test1234')
Looks like you are trying to do his backwards.
Per-condition: You need to define emit(someStr, someDict) somewhere.
Your MainClass need to extend ClassA.
Assuming you have class_a.py and main_app.py
main_app.py
from class_a import ClassA
class MainApp(ClassA):
## now you can call any method from ClassA
self.emitter(someArg)
Note: you don't need to MainApp.MainApp(self.emitter) in ClassA because MainApp extends ClassA.
Related
I am writing unit tests in python.
I am trying the following to make it a little more efficient.
caller
class TestTrait(TestCaseCommon):
APP_NAME = 'pytest'
HEADER = {'content-type': 'application/json'}
#mock.patch('dmp_graphql.utils.common_utils.get_test_user', return_value=TestCaseCommon.mock_get_role_check_test_user(role_type=AllUserRoleEnum.SUPERADMIN))
def test_get_all_categories_super_admin(self):
print(self)
implementation
class TestCaseCommon(TestCase):
def create_app(self):
return create_app(self.APP_NAME)
def setUp(self):
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
def mock_get_role_check_test_user(role_type: AllUserRoleEnum, is_not_exist_user: bool = False,
account_id: int = 0):
if is_not_exist_user:
return None
if role_type == AllUserRoleEnum.SUPERADMIN:
query = db.session.query(User).filter(User.is_super_admin == True)
else:
...
pass
return user
The following error occurred.
During handling of the above exception, another exception occurred:
test_create_traits_uploader.py:7: in <module>
class TestTrait(TestCaseCommon):
test_create_traits_uploader.py:11: in TestTrait
#mock.patch('dmp_graphql.utils.common_utils.get_test_user', return_value=TestCaseCommon.mock_get_role_check_test_user(role_type=AllUserRoleEnum.SUPERADMIN))
../common.py:35: in mock_get_role_check_test_user
query = db.session.query(User).filter(User.is_super_admin == True)
/Users/lhs/.local/share/virtualenvs/hyper-dmp-v2-api-y1V5yWAL/lib/python3.8/site-packages/sqlalchemy/orm/scoping.py:163: in do
return getattr(self.registry(), name)(*args, **kwargs)
/Users/lhs/.local/share/virtualenvs/hyper-dmp-v2-api-y1V5yWAL/lib/python3.8/site-packages/sqlalchemy/util/_collections.py:1022: in __call__
return self.registry.setdefault(key, self.createfunc())
/Users/lhs/.local/share/virtualenvs/hyper-dmp-v2-api-y1V5yWAL/lib/python3.8/site-packages/sqlalchemy/orm/session.py:3309: in __call__
return self.class_(**local_kw)
/Users/lhs/.local/share/virtualenvs/hyper-dmp-v2-api-y1V5yWAL/lib/python3.8/site-packages/flask_sqlalchemy/__init__.py:136: in __init__
self.app = app = db.get_app()
/Users/lhs/.local/share/virtualenvs/hyper-dmp-v2-api-y1V5yWAL/lib/python3.8/site-packages/flask_sqlalchemy/__init__.py:987: in get_app
raise RuntimeError(
E RuntimeError: No application found. Either work inside a view function or push an application context. See http://flask-sqlalchemy.pocoo.org/contexts/.
In the above situation, is there a way to share the app with the decorator?
Or I'd like to know if it's possible to implement it in another way.
The framework used is flask and the python version is 3.8.
I am trying to extend BaseHTTPRequestHandler with my own member variables. I pass these member variables to free functions but when I do so I get:
Exception happened during processing of request from ('127.0.0.1', 30006)
Traceback (most recent call last):
File "c:\Python37\lib\socketserver.py", line 313, in _handle_request_noblock
self.process_request(request, client_address)
File "c:\Python37\lib\socketserver.py", line 344, in process_request
self.finish_request(request, client_address)
File "c:\Python37\lib\socketserver.py", line 357, in finish_request
self.RequestHandlerClass(request, client_address, self)
File "fruiterer.py", line 41, in __init__
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
File "c:\Python37\lib\socketserver.py", line 712, in __init__
self.handle()
File "c:\Python37\lib\http\server.py", line 426, in handle
self.handle_one_request()
File "c:\Python37\lib\http\server.py", line 414, in handle_one_request
method()
File "fruiterer.py", line 62, in do_POST
fruit_handler(val, Event_dictionary_list, cached_timestamp)
NameError: name 'Event_dictionary_list' is not defined
Here is the python3 source code:
# sample python HTTP POST handler
__metaclass__= type
from http.server import BaseHTTPRequestHandler, HTTPServer
import os
import time
import threading
import requests
import json
def calculate(Event_dictionary_list, cached_timestamp):
# do a calculation here based on fruits in Event_dictionary_list
print("there are: %i items" % len(Event_dictionary_list))
Event_dictionary_list.clear() #- empty Event_dictionary_list
cached_timestamp = 0
def Async_func(Event_dictionary_list, cached_timestamp):
calculate(Event_dictionary_list, cached_timestamp)
def fruit_handler(event, Event_dictionary_list, cached_timestamp):
if not Event_dictionary_list: #Checking if Event_dictionary_list is empty
# cache first item added
cached_timestamp = event['timestamp']
#- set a 30 second timer
threading.Timer(60,Async_func, Event_dictionary_list, cached_timestamp).start()
# make decision as to when to calculate
if event['timestamp'] - cached_timestamp < 60*1000: #- in milliseconds
# append event to list
Event_dictionary_list.append(event)
#############################################################################################################
# we create a server to handle POST requests from Xovis
class fruiterer(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
BaseHTTPRequestHandler.__init__(self, *args, **kwargs)
self.Event_dictionary_list = []
self.cached_timestamp = 0
# we only need to support he POST http method
def do_POST(self):
#print("post msg received");
self.data_string = self.rfile.read(int(self.headers['Content-Length']))
self.send_response(200) # 200 = success - thanks for message response
#self.send_header() #'Content-type','text-html')
self.end_headers()
data = json.loads(self.data_string)
# we assume json will be decoded as object, eg:
# {"fruit":{"timestamp":1538688902037,"name":"apple","colour":"red","weight":100}}
if type(data) is dict:
for key, val in data.items():
# we are only interested in fruits
if key == "fruit":
fruit_handler(val, Event_dictionary_list, cached_timestamp)
break
return
def run():
print('http server is starting...')
# change port to listen on here - arbitrarily using port 7777
port = 7777
server_address = ('127.0.0.1', port)
#use the code from here .start()
httpd = HTTPServer(server_address, fruiterer)
print('http server is listening on port %d' % port)
httpd.serve_forever()
if __name__ == '__main__':
run()
This can be tested by sending the following json format in a POST body:
{"fruit":{"timestamp":1538688902037,"name":"apple","colour":"red","weight":100}}
What am I doing wrong?
You need to pass in self.Event_dictionary_list, not Event_dictionary_list, from your do_POST() method. The same would apply to cached_timestamp.
You'll then find that you'll get an AttributeError on self.Event_dictionary_list, because that attribute is never being set in your __init__ method. The documentation is a bit cryptic about this, but calling BaseHTTPRequestHandler.__init__(self, *args, **kwargs) triggers the handling of a single request, so the method doesn't return until after the request handlers have finished.
Move the setting of those attributes to before you call the base __init__ method:
class fruiterer(BaseHTTPRequestHandler):
def __init__(self, *args, **kwargs):
self.Event_dictionary_list = []
self.cached_timestamp = 0
super().__init__(*args, **kwargs)
I used the super().__init__() syntax here to allow for further co-operative inheritance in the future. You can still use BaseHTTPRequestHandler.__init__(self, *args, **kwargs) if you really want to, but the above is less verbose.
Do take into account that self.Event_dictionary_list = [] is run for each separate request.
If this object should live for the duration of your Python program (with the server running), make it a class attribute instead:
class fruiterer(BaseHTTPRequestHandler):
Event_dictionary_list = []
cached_timestamp = 0
Another issue is that setting cached_timestamp with cached_timestamp = ... in other functions will only alter a local variable. Integers are immmutable objects so you can only assign a new integer back to variables, but local variables in functions you call do not share a namespace with the request handler.
But if you wanted that value to persist across requests anyway, then you can just reference fruiterer.cached_timestamp everywhere and assign to that attribute directly.
I'm trying to build a small WSGI application with Werkzeug. I have followed this tutorial it's so simple and clear. However I encounter this error:
File "/Users/username/my_app/assigment2/app.py", line 38, in __init__
self.database_engine = create_engine(db_uri)
File "/Users/Data/lib/python3.4/site-packages/sqlalchemy/engine/__init__.py", line 386, in create_engine
return strategy.create(*args, **kwargs)
File "/Users/../lib/python3.4/site-packages/sqlalchemy/engine/strategies.py", line 51, in create
dialect_cls = u.get_dialect()
AttributeError: 'function' object has no attribute 'get_dialect'
I have imported all SqlAlchemy modules
from sqlalchemy import create_engine, MetaData
from sqlalchemy.orm import create_session, scoped_session
The application fails at the init of the app.
class App(object):
def __init__(self):
local.app = self
self.database_engine = create_engine(SQLALCHEMY_DATABASE_URI )
self.jinja_env = Environment(loader=PackageLoader('app', '/templates'))
self.dispatch = SharedDataMiddleware(self.dispatch, {'/static': STATIC_PATH})
def init_database(self):
metadata.create_all(self.database_engine)
def dispatch(self, environ, start_response):
local.app = self
request = Response(environ)
local.url_= adapter = url_map.bind_to_environ(environ)
#adapter = url_map.bind_to_environ(environ)
try:
endpoint, value = adapter.match()
handler = getattr(views, endpoint)
response = handler(request, **values)
except HTTPException as e:
response = e
return ClosingIterator(response(environ, strat_response),
[session.remove, local_manager.cleanup])
def __call__(self, environ, start_response):
return self.dispatch(environ, start_response)
the databse_uri looks like this
SQLALCHEMY_DATABASE_URI = 'postgresql://user:password#localhost:5432/name_db'
STATIC_PATH = path.join(path.dirname('/static'), 'static')
Why I can't create my app like this:
def make_app():
my_app = app.App()
return my_app
I am running on Gunicorn
gunicorn -b 127.0.0.1:9000 app:make_app
New error:
TypeError: make_app() takes 0 positional arguments but 2 were given
This is wrong:
gunicorn -b 127.0.0.1:9000 app:App
What happens when there is a request:
app.App(environ, start_response)
But what you really want is:
your_app = app.App(path, db_uri)
your_app(environ, start_response)
Change gunicorn invocation to something like this:
gunicorn -b 127.0.0.1:9000 'app:App("/static/path", "postgresql://...")'
I'm working to modify a cookiecutter Flask app. I'm currently trying to add a datepicker to a page. I've found https://eonasdan.github.io/bootstrap-datetimepicker/. This cookiecutter uses flask-assets to manage the project assets.
Following https://adambard.com/blog/fresh-flask-setup/ I've modified my assets.py file :
from flask_assets import Bundle, Environment
import os
css = Bundle(
"libs/bootstrap/dist/css/spacelab/bootstrap.css",
"bower_components/eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.css",
"css/style.css",
"css/home.css",
# "css/style.css",
filters="cssmin",
output="public/css/common.css"
)
js = Bundle(
"libs/jQuery/dist/jquery.js",
"libs/bootstrap/dist/js/bootstrap.js",
"bower_components/moment/moment.js",
"bower_components/eonasdan-bootstrap-datetimepicker/build/js/bootstrap-datetimepicker.min.js",
"js/plugins.js",
filters='jsmin',
output="public/js/common.js"
)
# Tell flask-assets where to look for our coffeescript and sass files.
assets = Environment()
assets.load_path = [os.path.join(os.path.dirname(__file__), 'myflaskapp/static/bower_components')]
assets.register("js_all", js)
assets.register("css_all", css)
When I do this I get:
Traceback (most recent call last):
File "C:/envs/r2/myproject/manage.py", line 8, in <module>
from myflaskapp.app import create_app
File "C:\envs\r2\myproject\myflaskapp\app.py", line 8, in <module>
from myflaskapp.assets import assets
File "C:\envs\r2\myproject\myflaskapp\assets.py", line 41, in <module>
assets.load_path = [os.path.join(os.path.dirname(__file__), 'myflaskapp/static/bower_components')]
File "C:\envs\virtalenvs\flask_myproject\lib\site-packages\webassets\env.py", line 639, in _set_load_path
self._storage['load_path'] = load_path
File "C:\envs\virtalenvs\flask_myproject\lib\site-packages\flask_assets.py", line 104, in __setitem__
self.env._app.config[self._transform_key(key)] = value
File "C:\envs\virtalenvs\flask_myproject\lib\site-packages\flask_assets.py", line 292, in _app
'and no application in current context')
RuntimeError: assets instance not bound to an application, and no application in current context
What am I doing wrong?
edit: app.py initializes the assets:
from flask import Flask, render_template
from myflaskapp.assets import assets
:param config_object: The configuration object to use.
"""
app = Flask(__name__)
app.config.from_object(config_object)
register_extensions(app)
register_blueprints(app)
register_errorhandlers(app)
return app
def register_extensions(app):
assets.init_app(app)
def register_blueprints(app):
app.register_blueprint(public.blueprint)
app.register_blueprint(user.blueprint)
As I noted in my comment, you have to a Flask app bound to the object, as it notes in the traceback:
>>> RuntimeError: assets instance not bound to an application, and no
application in current context
This will fix your problem, whether or not it's relevant for you use case...:
def register_extensions(app):
assets.init_app(app)
with app.app_context():
assets.load_path = ['static']
or you could re-write your create app to have
def create_assets(app):
assets = Environment(app)
....
assets.load_path ['static']
return assets
def create_app():
app = Flask()
....
assets = create_assets(app)
return app
The whole reason for your errors is your call to load_path. This tries to set the attribute in webassets, which you can see here: https://github.com/miracle2k/webassets/blob/95dff0ad6dcc25b81790a1585c67f5393e7d32af/src/webassets/env.py#L656
def _set_load_path(self, load_path):
self._storage['load_path'] = load_path
In turn, this now activates the attribute of _storage on your flask-asset object, which results in it trying to do this: https://github.com/miracle2k/flask-assets/blob/eb7f1905410828689086b80eb19be9331041ac52/src/flask_assets.py#L102
def __setitem__(self, key, value):
if not self._set_deprecated(key, value):
self.env._app.config[self._transform_key(key)] = value
As you see, it needs access to an app, and as you haven't given one when you used load_path it will complain to you, as it explains so nicely in the Traceback. I found a discussion about this on the flask-asset page: https://github.com/miracle2k/flask-assets/issues/35
You may, quite rightly, think that as you called init_app() that everything should be fine, but that's not the case, init_app() does not give any reference of the app to Environment: https://github.com/miracle2k/flask-assets/blob/eb7f1905410828689086b80eb19be9331041ac52/src/flask_assets.py#L338
def init_app(self, app):
app.jinja_env.add_extension('webassets.ext.jinja2.AssetsExtension')
app.jinja_env.assets_environment = self
I don't use flask-assets at all, and so I'm not particularly sure why they haven't referenced the app with the Environment().init_app, so if someone else knows, shout out.
This question already has answers here:
Deriving a class from TestCase throws two errors
(2 answers)
Closed 6 years ago.
I have this plain vanilla unit test, which works as expected, as long I leave out the constructor.
import sys
import unittest
class Instance_test(unittest.TestCase):
def __init__(self):
super(Instance_test, self).__init__()
self.attribute = "new"
def test_something(self):
pass
def test_other(self):
self.assertTrue(True)
pass
def setUp(self):
pass
def tearDown(self):
pass
def suite():
return unittest.makeSuite(Instance_test, "test")
def main():
runner = unittest.TextTestRunner(sys.stdout)
runner.run(suite())
if __name__ == "__main__":
main()
With the constructor in place in get this backtrace:
Traceback (most recent call last):
File "f:\gt\check.py", line 31, in main()
File "f:\gt\check.py", line 28, in main
runner.run(suite())
File "f:\gt\check.py", line 24, in suite
return unittest.makeSuite(Instance_test, "test")
File "C:\Python34\lib\unittest\loader.py", line 374, in makeSuite
testCaseClass)
File "C:\Python34\lib\unittest\loader.py", line 70, in loadTestsFromTestCase
loaded_suite = self.suiteClass(map(testCaseClass, testCaseNames))
File "C:\Python34\lib\unittest\suite.py", line 24, in __init__
self.addTests(tests)
File "C:\Python34\lib\unittest\suite.py", line 60, in addTests
for test in tests:
TypeError: __init__() takes 1 positional argument but 2 were given
What's wrong and how else could I have a central attribute to be shared by different test_xxx methods?
I would use unittest.TestCase's setUp() and tearDown() methods instead of init. Just do the same thing you're doing except use the setUp method.
It is happening because __init__ takes more than one arguments, you forgot to provide args and kwargs as arguments. It should have been like this -
class Instance_test(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(Instance_test, self).__init__(*args, **kwargs)
self.attribute = "new"
Besides why are you overriding __init__ anyway (as 2achary suggested) when setUp method is exactly meant for this purpose.
class Instance_test(unittest.TestCase):
def setUp(self):
self.attribute = 'new'
Just add an argument named methodName to your own __init__ method and you should be good to go:
class Instance_test(unittest.TestCase):
def __init__(self, methodName='runTest'):
super(Instance_test, self).__init__(methodName=methodName)
self.attribute = "new"
...
The base TestCase.__init__ signature is as follows:
class TestCase(object):
def __init__(self, methodName='runTest'):
...
As you can see, it takes an additional methodName argument, and there is no constructor without it, hence the failure you encountered.