forked from zackees/template-docker-fastapi-site
-
Notifications
You must be signed in to change notification settings - Fork 0
/
run_dev.py
128 lines (102 loc) · 3.77 KB
/
run_dev.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
"""
Setup development environment
"""
import atexit
import os
import subprocess
import sys
import threading
import time
import webbrowser
import requests # type: ignore
import uvicorn # pylint: disable=import-error
HERE = os.path.dirname(os.path.abspath(__file__))
os.chdir(HERE)
os.environ["IS_TEST"] = "1"
FASTAPI_PORT = 8000
APP_NAME = "mediabiasscorer"
FASTAPI_APP = f"{APP_NAME}.app:app"
FASTAPI_RELOAD = False # Reload doesn't work well with VSCode auto-save feature.
NPM_SERVER_PORT = 4999
def run_uvicorn() -> None:
"""Run the Uvicorn server."""
uvicorn.run(FASTAPI_APP, host="localhost", port=FASTAPI_PORT, reload=FASTAPI_RELOAD)
def run_open_browser() -> None:
time.sleep(1)
# Wait for the server to start
while True:
try:
requests.get(f"http://localhost:{FASTAPI_PORT}", timeout=60)
break
except requests.exceptions.ConnectionError:
pass
webbrowser.open(f"http://localhost:{FASTAPI_PORT}")
def run_npm_server() -> None:
"""Run the npm server."""
proc = subprocess.Popen(f"npm run start -- --port {NPM_SERVER_PORT}", shell=True, cwd="www")
atexit.register(proc.kill)
time.sleep(10)
rtn = proc.poll()
if rtn is not None:
sys.stderr.write("npm server failed to start.\n")
sys.exit(1)
def run_background_tasks() -> None:
"""Run the background tasks."""
data: list[subprocess.Popen] = list()
def kill_proc() -> None:
if data:
proc = data[0]
proc.kill()
atexit.register(kill_proc)
while True:
proc = subprocess.Popen(f"python -m {APP_NAME}.background_tasks", shell=True, cwd=HERE)
if len(data) == 0:
data.append(proc)
else:
data[0] = proc
while proc.poll() is None:
time.sleep(1)
def check_python_dependencies() -> bool:
"""Check all dependencies."""
# get requirements from requirements.txt
with open("requirements.txt", encoding="utf-8", mode="r") as f:
requirements = f.read().splitlines()
# now add in requirements from requirements.testing.txt
with open("requirements.testing.txt", encoding="utf-8", mode="r") as f:
requirements += f.read().splitlines()
# remove comments
requirements = [r.split("#")[0].strip() for r in requirements]
# parse out all the package names
packages = [r.split("==")[0].strip() for r in requirements]
packages = [p.strip() for p in packages if p.strip()]
# clear out empty strings
packages = [p for p in packages if p]
# check each package
import pkg_resources # pylint: disable=import-outside-toplevel
any_uninstalled = False
for package in packages:
try:
_ = pkg_resources.get_distribution(package)
# print(f"{dist.key} ({dist.version}) is installed")
except pkg_resources.DistributionNotFound:
print(f"{package} is NOT installed")
any_uninstalled = True
return any_uninstalled
def install_deps() -> None:
python_exe = sys.executable
subprocess.run(f"{python_exe} -m pip install -e .", shell=True, cwd=HERE, check=False)
ANY_PYTHON_DEPS_UNINSTALLED = check_python_dependencies()
if ANY_PYTHON_DEPS_UNINSTALLED:
print("Installing dependencies...")
install_deps()
os.system("cd www && npm install")
# Set environmental variable for internal proxy
os.environ["NPM_SERVER"] = f"http://localhost:{NPM_SERVER_PORT}"
# Manager server processes in a separate thread.
threading.Thread(target=run_npm_server, daemon=True).start()
threading.Thread(target=run_open_browser, daemon=True).start()
threading.Thread(target=run_background_tasks, daemon=True).start()
time.sleep(7) # give time for the npm server to start.
threading.Thread(target=run_uvicorn, daemon=True).start()
while True:
time.sleep(10)