Error trying to use global variable from Bottlepy mounted app - python

I got a parent_app in a python file (parent.py) that I'm trying to mount in a child_app in another python file (child.py). The mount seems to work but, when I try to call a route from my parent_app trough the mount in my child_app, this route doesn't seems to be able to use global variable in my parent.py file.
The parent.py file:
from bottle import route
import bottle
import subprocess as sp
global extProc
parent_app = bottle.Bottle()
#parent_app.route('/start')
def start_bazarr():
global extProc
extProc = sp.Popen(['python','child.py'])
#parent_app.route('/stop')
def stop_bazarr():
sp.Popen.terminate(extProc)
#parent_app.route('/restart')
def restart_bazarr():
stop_bazarr()
start_bazarr()
if __name__ == '__main__':
start_bazarr()
The child.py file:
from bottle import route, run
import bottle
from parent import parent_app
child_app = bottle.Bottle()
#child_app.route('/')
def root():
return u'Lorem Ipsum'
if __name__ == '__main__':
child_app.mount('/power', parent_app)
child_app.run(host='127.0.0.1', port=8080)
The URL I'm trying to call:
http://127.0.0.1:8080/power/restart
The error I got:
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\bottle.py", line 862, in _handle
return route.call(**args)
File "C:\Python27\lib\site-packages\bottle.py", line 1740, in wrapper
rv = callback(*a, **ka)
File "C:\Users\morpheus\Desktop\parent.py", line 20, in restart_bazarr
stop_bazarr()
File "C:\Users\morpheus\Desktop\parent.py", line 16, in stop_bazarr
sp.Popen.terminate(extProc)
NameError: global name 'extProc' is not defined
What am I doing wrong?

In the global scope, you don't need the global keyword. You can define it , and set it to None as a temporary placeholder.
from bottle import route
import bottle
import subprocess as sp
extProc = None
And the terminate function needs to know about the use of extProc
#parent_app.route('/stop')
def stop_bazarr():
global extProc
sp.Popen.terminate(extProc)

Related

Launch flask python file from main python file

I have a flask python file that i want to open when i start the main python file.
main python file
start flask python file
continue with it's own independent processes (threading)
Which solution to take since i do not want the execution of the flask app to hinder the performance of the later processes. Not sure if i should do a subprocess or exec file?
both files are pretty independent of each other.
if I understood correctly, you can create a daemon thread for flask and continue with the execution of main program.
If you have a independent_module.py like this:
# independent_module.py
# your independent functions
def start():
pass
Then your main file would look something like this:
# main.py file
import threading
from flask import Flask
import main
app = Flask(__name__)
#app.route("/health")
def health():
return "OK"
#app.route("/ping")
def ping():
return "Et. Voila!!"
def run_server_api():
app.run(host='0.0.0.0', port=8080)
def main():
flask_thread = threading.Thread(target=run_server_api, daemon=True)
flask_thread.start()
# continue with your main program functions
independent_module.start()
if __name__ == "__main__":
# execute main
main()
You can simply execute python main.py

python unittest ModuleNotFoundError: No module named <...>

I tried to crate simple Python project with flask and unittest. Structure is quite simple:
classes
|-sysinfo
|static
|templates
|- index.html
|- layout.html
|__init__.py
|sysinfo.py
|printinfo.py
tests
|test_sysinfo.py
README.md
requirments.txt
Very simple class in printinfo.py:
#!/usr/bin/python
import psutil
import json
class SysInfo:
.......
def displayInfo(self):
.......
return json.dumps(self.__data)
And simple flask server run with sysinfo.py:
from flask import Flask, flash, redirect, render_template, request, session, abort
from printinfo import SysInfo
import json
obj1 = SysInfo("gb")
app = Flask(__name__)
#app.route('/')
def index():
var = json.loads(obj1.displayInfo())
return render_template('index.html',**locals())
#app.route('/healthcheck')
def healthcheck():
return "Ok"
#app.route("/api/all")
def all():
return obj1.displayInfo()
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
del obj1
I run it with python sysinfo.py staying in classes/sysinfo folder and everything works ok.
So I decided to run unittest for my application. Put in classes/tests ( also tried classes/sysinfo/tests) file test_sysinfo.py with code:
import unittest
import printinfo
from sysinfo import sysinfo
import json
import sys
class TestFlaskApi(unittest.TestCase):
def setUp(self):
self.app = sysinfo.app.test_client()
def simple_test(self):
response = self.app.get('/health')
self.assertEqual(
json.loads(response.get_data().decode(sys.getdefaultencoding())),
{'healthcheck': 'ok'}
)
if __name__ == "__main__":
unittest.main()
And when I started it I can see error:
Error Traceback (most recent call last):
File "\Python\Python37-32\lib\unittest\case.py", line 59, in testPartExecutor
yield File "\Python\Python37-32\lib\unittest\case.py", line 615, in run
testMethod() File "\Python\Python37-32\lib\unittest\loader.py", line 34, in testFailure
raise self._exception ImportError: Failed to import test module: test_sysinfo Traceback (most recent call last): File
"\Python\Python37-32\lib\unittest\loader.py", line 154, in
loadTestsFromName
module = __import__(module_name) File "\classes\sysinfo\tests\test_sysinfo.py", line 2, in <module>
import printinfo ModuleNotFoundError: No module named 'printinfo'
I read several articles, some topics here on StackOverflow for my understanding it's related to project structure. I tried to create setup.py and setup.cfg. I managed to start it with this setup, but test still didn't work.
Could you please help me with minimum setup applicable for my case? All the material I found had written for specific case or too general. I cannot apply it for my case.
Follow flask tutorial I edit __init__.py file to start app from here:
from flask import Flask, flash, redirect, render_template, request, session, abort
from . import printinfo
import json
import os
obj1 = printinfo.SysInfo("gb")
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY='dev'
)
obj1 = printinfo.SysInfo("gb")
#app.route('/')
def index():
var = json.loads(obj1.displayInfo())
return render_template('index.html', **locals())
#app.route('/healthcheck')
def healthcheck():
return "Ok"
#app.route("/api/all")
def all():
return obj1.displayInfo()
#del obj1
return app
Also environment variables should be set for Flask:
For Linux and Mac:
export FLASK_APP=sysinfo
export FLASK_ENV=development
For Windows cmd, use set instead of export:
set FLASK_APP=sysinfo
set FLASK_ENV=development
And run application:
flask run
It run application on localhost on port 5000 since development env set. Anyway I needed to add from . import printinfo into __init__.py.
Didn't try test, but think it should work. If interesting will update soon.
Just followed Flask tutorial. Created conftest.py and test_factory.py. Run Ok with pytest:
import pytest
from sysinfo import create_app
from sysinfo import printinfo
#pytest.fixture
def app():
app = create_app({
'TESTING': True
})
with app.app_context():
printinfo.SysInfo("gb")
yield app
Probably the same setup could be used with unittest. Didn't try.

Windows service with Flask only run in DEBUG mode. Normal mode seem crash

I want to install python script (use Flask) as Windows service.
I use simple code as below (in myservice.py) :
import win32serviceutil
import win32service
import win32event
import win32evtlogutil
import servicemanager
import socket
import time
import logging
from multiprocessing import Process
import traceback
import logging
from datetime import datetime,tzinfo,timedelta
from flask import Flask
import os
import sys
sys.path.append(os.path.dirname(__name__))
app = Flask(__name__)
class Zone(tzinfo):
def __init__(self,offset,isdst,name):
self.offset = offset
self.isdst = isdst
self.name = name
def utcoffset(self, dt):
return timedelta(hours=self.offset) + self.dst(dt)
def dst(self, dt):
return timedelta(hours=1) if self.isdst else timedelta(0)
def tzname(self,dt):
return self.name
#app.route('/')
def hello_world():
logging.info('[GET] hello_world ...')
KST = Zone(+9,False,'KST')
now_time = datetime.now(KST).strftime('%Y-%m-%d %H:%M:%S %Z')
return 'Hello, World! ' + now_time
logging.basicConfig(
filename = 'c:\\Temp\\hello-service.log',
level = logging.DEBUG,
format = '[helloflask] %(levelname)-7.7s %(message)s'
)
class HelloFlaskSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "AIHello"
_svc_display_name_ = "AI Hello"
def __init__(self, *args):
win32serviceutil.ServiceFramework.__init__(self, *args)
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
#socket.setdefaulttimeout(5)
self.stop_requested = False
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
#self.process.terminate()
win32event.SetEvent(self.hWaitStop)
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
logging.info('Stopped service ...')
self.stop_requested = True
def SvcDoRun(self):
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_,'')
)
logging.info('Before main')
app.run()
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(HelloFlaskSvc)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(HelloFlaskSvc)
I can install this script by command : python.exe myservice.py -install, it show up in Services list, but when i try to start it say "The AI Hello service on Local Computer started and then stopped. Some service stop automatically if they are not in use by other services or program".
I checked Event Viewer log, it show " The instance's SvcRun() method failed
.Error getting traceback - traceback.print_exception() failed %2: %3"
I am using Python 3.6.4 , Flask 1.0.2, pywin32-224, on Windows 10 64bit.
This script can work in DEBUG mode by command: python myservice.py debug
Hope somebody can help me out, please
Updated: I switched to Python 2.7. It show the same error. But in Event Viewer log:
The instance's SvcRun() method failed
Traceback (most recent call last):
File "C:\Python27\lib\site-packages\win32\lib\win32serviceutil.py", line 839, in SvcRun
self.SvcDoRun()
File "D:\MusFatAI\FlaskServiceWin32-master\FlaskServiceWin32-master\win32_service.py", line 73, in SvcDoRun
app.run(debug=False)
File "C:\Python27\lib\site-packages\flask\app.py", line 938, in run
cli.show_server_banner(self.env, self.debug, self.name, False)
File "C:\Python27\lib\site-packages\flask\cli.py", line 629, in show_server_banner
click.echo(message)
File "C:\Python27\lib\site-packages\click\utils.py", line 261, in echo
file.flush()
IOError: (9, 'Bad file descriptor')
I had similar problem and I fixed it by putting this line on top of the script:
sys.stdout = sys.stderr = open(os.devnull, 'w')

Issue with unit test for tiny Flask app

I have a very primitive Flask application which works as I'm expecting, but I'm failing to write a unit test for it. The code of the app is following (i omit insignificant part):
app.py
from flask import *
import random
import string
app = Flask(__name__)
keys = []
app.testing = True
#app.route('/keygen/api/keys', methods=['POST'])
def create():
symbol = string.ascii_letters + string.digits
key = ''.join(random.choice(symbol) for _ in range(4))
key_instance = {'key': key, 'is_used': False}
keys.append(key_instance)
return jsonify({'keys': keys}), 201
The test is:
tests.py
import unittest
from flask import *
import app
class TestCase(unittest.TestCase):
def test_number_one(self):
test_app = Flask(app)
with test_app.test_client() as client:
rv = client.post('/keygen/api/keys')
...something...
if __name__ == '__main__':
unittest.main()
The traceback:
ERROR: test_number_one (__main__.TestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 12, in test_number_one
test_app = Flask(app)
File "/Users/bulrathi/Yandex.Disk.localized/Virtualenvs/ailove/lib/python3.5/site-packages/flask/app.py", line 346, in __init__
root_path=root_path)
File "/Users/bulrathi/Yandex.Disk.localized/Virtualenvs/ailove/lib/python3.5/site-packages/flask/helpers.py", line 807, in __init__
root_path = get_root_path(self.import_name)
File "/Users/bulrathi/Yandex.Disk.localized/Virtualenvs/ailove/lib/python3.5/site-packages/flask/helpers.py", line 668, in get_root_path
filepath = loader.get_filename(import_name)
File "<frozen importlib._bootstrap_external>", line 384, in _check_name_wrapper
ImportError: loader for app cannot handle <module 'app' from '/Users/bulrathi/Yandex.Disk.localized/Обучение/Code/Django practice/ailove/keygen/app.py'>
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (errors=1)
Thanks for your time.
You have a few issues with the posted code (indentation aside):
First, in tests.py you import app and use it, but app is the module rather than the app object from app.py. You should import the actual app object using
from app import app
and secondly, you are using that app object (assuming we fix the import) as a parameter to another Flask() constructor—essentially saying:
app = Flask(Flask(app))
Since we've imported app from app.py, we can just use it directly, so we remove the app = Flask(app) line (and the associated import statement as we don't need it anymore) and your test file becomes:
import unittest
from app import app
class TestCase(unittest.TestCase):
def test_number_one(self):
with app.test_client() as client:
rv = client.post('/keygen/api/keys')
...something...
if __name__ == '__main__':
unittest.main()
You should note also that the from flask import * form is discouraged in favour of importing specific parts of the module, so
from flask import Flask, jsonify
would be better in your app.py.

Flask: cannot import name 'app'

Trying to run my python file updater.py to SSH to a server and run some commands every few set intervals or so. I'm using APScheduler to run the function update_printer() from __init__.py. Initially I got a working outside of application context error but someone suggested that I just import app from __init__.py. However it isn't working out so well. I keep getting a cannot import name 'app' error.
app.py
from queue_app import app
if __name__ == '__main__':
app.run(debug=True)
__init__.py
from flask import Flask, render_template
from apscheduler.schedulers.background import BackgroundScheduler
from queue_app.updater import update_printer
app = Flask(__name__)
app.config.from_object('config')
#app.before_first_request
def init():
sched = BackgroundScheduler()
sched.start()
sched.add_job(update_printer, 'interval', seconds=10)
#app.route('/')
def index():
return render_template('index.html')
updater.py
import paramiko
import json
from queue_app import app
def update_printer():
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(app.config['SSH_SERVER'], username = app.config['SSH_USERNAME'], password = app.config['SSH_PASSWORD'])
...
File Structure
queue/
app.py
config.py
queue_app/
__init__.py
updater.py
Error
Traceback (most recent call last):
File "app.py", line 1, in <module>
from queue_app import app
File "/Users/name/queue/queue_app/__init__.py", line 3, in <module>
from queue_app.updater import update_printer
File "/Users/name/queue/queue_app/updater.py", line 3, in <module>
from queue_app import app
ImportError: cannot import name 'app'
What do I need to do be able to get to the app.config from updater.py and avoid a "working outside of application context error" if ran from APScheduler?
It's a circular dependency, as you import updater in your __init__.py file. In my Flask setup, app is created in app.py.

Categories

Resources