Remove dependency on requests library.

Change auto reloader enviroment varible name to SANIC_SERVER_RUNNING
Fix some typo mistakes, flake uncompatibilities and such problems.
Raise NotImplementedError for operating systems except posix systems for auto reloading.
This commit is contained in:
Yaser Amiri 2017-12-26 19:17:13 +03:30
parent 3fe3c2c79f
commit 81494453b0
8 changed files with 68 additions and 39 deletions

View File

@ -645,8 +645,13 @@ class Sanic:
try:
self.is_running = True
if workers == 1:
if os.name == 'posix' and auto_reload and \
os.environ.get('MAIN_PROCESS_RUNNED') != 'true':
if auto_reload and os.name != 'posix':
# This condition must be removed after implementing
# auto reloader for other operating systems.
raise NotImplementedError
if auto_reload and \
os.environ.get('SANIC_SERVER_RUNNING') != 'true':
reloader_helpers.watchdog(2)
else:
serve(**server_settings)
@ -808,14 +813,14 @@ class Sanic:
logger.setLevel(logging.DEBUG)
if self.config.LOGO is not None and \
os.environ.get('MAIN_PROCESS_RUNNED') != 'true':
os.environ.get('SANIC_SERVER_RUNNING') != 'true':
logger.debug(self.config.LOGO)
if run_async:
server_settings['run_async'] = True
# Serve
if host and port and os.environ.get('MAIN_PROCESS_RUNNED') != 'true':
if host and port and os.environ.get('SANIC_SERVER_RUNNING') != 'true':
proto = "http"
if ssl is not None:
proto = "https"

View File

@ -7,7 +7,9 @@ from multiprocessing import Process
def _iter_module_files():
"""This iterates over all relevant Python files. It goes through all
"""This iterates over all relevant Python files.
It goes through all
loaded files from modules, all files in folders of already loaded modules
as well as all files reachable through a package.
"""
@ -38,12 +40,12 @@ def _get_args_for_reloading():
def restart_with_reloader():
"""Create a new process and a subprocess in it
with the same arguments as this one.
"""Create a new process and a subprocess in it with the same arguments as
this one.
"""
args = _get_args_for_reloading()
new_environ = os.environ.copy()
new_environ['MAIN_PROCESS_RUNNED'] = 'true'
new_environ['SANIC_SERVER_RUNNING'] = 'true'
cmd = ' '.join(args)
worker_process = Process(
target=subprocess.call, args=(cmd,),
@ -58,7 +60,7 @@ def kill_process_children_unix(pid):
:param pid: PID of process (process ID)
:return: Nothing
"""
root_process_path = "/proc/%s/task/%s/children" % (pid, pid)
root_process_path = "/proc/{pid}/task/{pid}/children".format(pid=pid)
if not os.path.isfile(root_process_path):
return
with open(root_process_path) as children_list_file:
@ -87,12 +89,11 @@ def kill_program_completly(proc):
def watchdog(sleep_interval):
"""Whatch project files, restart worker process if a change happened.
"""Watch project files, restart worker process if a change happened.
:param sleep_interval: interval in second.
:return: Nothing
"""
mtimes = {}
worker_process = restart_with_reloader()
signal.signal(

View File

@ -3,10 +3,13 @@ import sys
import subprocess
import signal
from threading import Thread
import requests
from time import sleep
from json.decoder import JSONDecodeError
import aiohttp
import asyncio
import async_timeout
sanic_project_content_one = '''
sanic_project_content_one = '''
from sanic import Sanic
from sanic import response
@ -22,7 +25,7 @@ if __name__ == '__main__':
app.run(host="127.0.0.1", port=8000, auto_reload=True)
'''
sanic_project_content_two = '''
sanic_project_content_two = '''
from sanic import Sanic
from sanic import response
@ -39,6 +42,8 @@ if __name__ == '__main__':
'''
process_id = None
def execute_cmd(command):
process = subprocess.Popen(command, shell=True)
global process_id
@ -48,38 +53,56 @@ def execute_cmd(command):
class TestAutoReloading:
def test_reloading_after_change_file(self,capsys):
def check_response(self, url, response):
"""Send http request and tries to take it's response as json.
Returns a dictionary.
"""
async def req(url, excepted_response):
async with aiohttp.ClientSession() as session:
with async_timeout.timeout(10):
async with session.get(url) as response:
try:
result = await response.json()
except JSONDecodeError:
result = {}
return result == excepted_response
loop = asyncio.get_event_loop()
return loop.run_until_complete(req(url, response))
def test_reloading_after_change_file(self, capsys):
if os.name != 'posix':
return
with capsys.disabled(): pass
with capsys.disabled():
pass
sanic_app_file_path = "simple_sanic_app.py"
with open (sanic_app_file_path, "w") as _file:
with open(sanic_app_file_path, "w") as _file:
_file.write(sanic_project_content_one)
cmd = ' '.join([sys.executable, sanic_app_file_path])
thread = Thread(target=execute_cmd, args=(cmd,))
thread.start()
sleep(2) # wait for completing server start process
response = requests.get("http://127.0.0.1:8000/").json()
assert response == {"test": 1}
sleep(2) # wait for completing server start process
assert self.check_response("http://127.0.0.1:8000/", {"test": 1})
with open (sanic_app_file_path, "w") as _file:
with open(sanic_app_file_path, "w") as _file:
_file.write(sanic_project_content_two)
sleep(2) # wait for completing server start process
response = requests.get("http://127.0.0.1:8000/").json()
assert response == {"test": 2}
sleep(2) # wait for completing server start process
assert self.check_response("http://127.0.0.1:8000/", {"test": 2})
thread.join(1)
os.remove(sanic_app_file_path)
def teardown_method(self, method):
if process_id:
root_proc_path = "/proc/%s/task/%s/children" % (process_id, process_id)
if not os.path.isfile(root_proc_path):
return
with open(root_proc_path) as children_list_file:
children_list_pid = children_list_file.read().split()
for child_pid in children_list_pid:
os.kill(int(child_pid), signal.SIGTERM)
if process_id:
root_proc_path = \
"/proc/{pid}/task/{pid}/children".format(pid=process_id)
if not os.path.isfile(root_proc_path):
return
with open(root_proc_path) as children_list_file:
children_list_pid = children_list_file.read().split()
for child_pid in children_list_pid:
os.kill(int(child_pid), signal.SIGTERM)

View File

@ -68,7 +68,7 @@ class ReuseableSanicTestClient(SanicTestClient):
import traceback
traceback.print_tb(e2.__traceback__)
exceptions.append(e2)
#Don't stop here! self.app.stop()
# Don't stop here! self.app.stop()
if self._server is not None:
_server = self._server
@ -266,4 +266,3 @@ def test_keep_alive_server_timeout():
assert isinstance(exception, ValueError)
assert "Connection reset" in exception.args[0] or \
"got a new connection" in exception.args[0]

View File

@ -75,6 +75,7 @@ def test_middleware_response_exception():
assert response.text == 'OK'
assert result['status_code'] == 404
def test_middleware_override_request():
app = Sanic('test_middleware_override_request')
@ -109,7 +110,6 @@ def test_middleware_override_response():
assert response.text == 'OK'
def test_middleware_order():
app = Sanic('test_middleware_order')
@ -146,4 +146,4 @@ def test_middleware_order():
request, response = app.test_client.get('/')
assert response.status == 200
assert order == [1,2,3,4,5,6]
assert order == [1, 2, 3, 4, 5, 6]

View File

@ -20,7 +20,8 @@ def test_storage():
@app.route('/')
def handler(request):
return json({'user': request.get('user'), 'sidekick': request.get('sidekick')})
return json({'user': request.get('user'),
'sidekick': request.get('sidekick')})
request, response = app.test_client.get('/')

View File

@ -188,7 +188,8 @@ def test_request_stream_handle_exception():
# 405
request, response = app.test_client.get('/post/random_id', data=data)
assert response.status == 405
assert response.text == 'Error: Method GET not allowed for URL /post/random_id'
assert response.text == \
'Error: Method GET not allowed for URL /post/random_id'
def test_request_stream_blueprint():

View File

@ -16,7 +16,6 @@ deps =
chardet<=2.3.0
beautifulsoup4
gunicorn
requests
commands =
pytest tests --cov sanic --cov-report= {posargs}
- coverage combine --append