Compare commits
3 Commits
90665f1491
...
7bbd4a5789
Author | SHA1 | Date |
---|---|---|
simon | 7bbd4a5789 | |
simon | 5103d08b0a | |
simon | 646d2ae972 |
|
@ -0,0 +1,115 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
""" check requirements.txt for outdated packages """
|
||||||
|
|
||||||
|
import pathlib
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
|
||||||
|
class Requirements:
|
||||||
|
"""handle requirements.txt"""
|
||||||
|
|
||||||
|
FILE_PATH = "web/requirements.txt"
|
||||||
|
LOCK = "/tmp/air-requirements.lock"
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.exists = self.checked_today()
|
||||||
|
self.all_requirements = False
|
||||||
|
self.all_updates = False
|
||||||
|
|
||||||
|
def checked_today(self):
|
||||||
|
"""skip requirements check when lock file exists"""
|
||||||
|
exists = pathlib.Path(self.LOCK).exists()
|
||||||
|
return exists
|
||||||
|
|
||||||
|
def look_for_updates(self):
|
||||||
|
"""look through requirements and check for updates"""
|
||||||
|
self.all_requirements = self.get_dependencies()
|
||||||
|
self.all_updates = self.check_packages()
|
||||||
|
|
||||||
|
def get_dependencies(self):
|
||||||
|
"""read out requirements.txt"""
|
||||||
|
|
||||||
|
all_requirements = []
|
||||||
|
with open(self.FILE_PATH, "r", encoding="utf-8") as f:
|
||||||
|
dependencies = f.readlines()
|
||||||
|
|
||||||
|
for dependency in dependencies:
|
||||||
|
package, version = dependency.split("==")
|
||||||
|
all_requirements.append((package, version.strip()))
|
||||||
|
|
||||||
|
all_requirements.sort(key=lambda x: x[0].lower())
|
||||||
|
|
||||||
|
return all_requirements
|
||||||
|
|
||||||
|
def check_packages(self):
|
||||||
|
"""compare installed with remote version"""
|
||||||
|
|
||||||
|
total = len(self.all_requirements)
|
||||||
|
print(f"checking versions for {total} packages...")
|
||||||
|
|
||||||
|
all_updates = {}
|
||||||
|
|
||||||
|
for dependency in self.all_requirements:
|
||||||
|
package, version_installed = dependency
|
||||||
|
url = f"https://pypi.org/pypi/{package}/json"
|
||||||
|
response = requests.get(url).json()
|
||||||
|
version_remote = response["info"]["version"]
|
||||||
|
homepage = response["info"]["home_page"]
|
||||||
|
if version_remote != version_installed:
|
||||||
|
to_update = {
|
||||||
|
package: {"from": version_installed, "to": version_remote}
|
||||||
|
}
|
||||||
|
all_updates.update(to_update)
|
||||||
|
message = (
|
||||||
|
f"update {package} {version_installed}"
|
||||||
|
+ f"==> {version_remote}\n {homepage}"
|
||||||
|
)
|
||||||
|
print(message)
|
||||||
|
|
||||||
|
if not all_updates:
|
||||||
|
print("no updates found")
|
||||||
|
|
||||||
|
# remember that
|
||||||
|
pathlib.Path(self.LOCK).touch()
|
||||||
|
|
||||||
|
return all_updates
|
||||||
|
|
||||||
|
def apply_updates(self):
|
||||||
|
"""update requirements.txt file with new versions"""
|
||||||
|
|
||||||
|
to_write = []
|
||||||
|
|
||||||
|
for requirement in self.all_requirements:
|
||||||
|
package, old_version = requirement
|
||||||
|
|
||||||
|
if package in self.all_updates.keys():
|
||||||
|
package_version = self.all_updates[package]["to"]
|
||||||
|
else:
|
||||||
|
package_version = old_version
|
||||||
|
|
||||||
|
to_write.append(f"{package}=={package_version}\n")
|
||||||
|
|
||||||
|
with open(self.FILE_PATH, "w", encoding="utf-8") as f:
|
||||||
|
f.writelines(to_write)
|
||||||
|
|
||||||
|
print("requirements.txt updates")
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""main to check for updates"""
|
||||||
|
handler = Requirements()
|
||||||
|
if handler.exists:
|
||||||
|
return
|
||||||
|
|
||||||
|
handler.look_for_updates()
|
||||||
|
if handler.all_updates:
|
||||||
|
input_response = input("\nupdate requirements.txt? [y/n] ")
|
||||||
|
if input_response == "y":
|
||||||
|
handler.apply_updates()
|
||||||
|
else:
|
||||||
|
print("skip update...")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -1,12 +1,12 @@
|
||||||
APScheduler
|
APScheduler==3.10.0
|
||||||
Flask_HTTPAuth
|
Flask_HTTPAuth==4.7.0
|
||||||
Flask_Table
|
Flask_Table==0.5.0
|
||||||
Flask
|
Flask==2.2.2
|
||||||
matplotlib
|
ipython==8.9.0
|
||||||
numpy
|
matplotlib==3.6.3
|
||||||
pandas
|
numpy==1.24.2
|
||||||
psycopg2-binary
|
pandas==1.5.3
|
||||||
requests
|
psycopg2-binary==2.9.5
|
||||||
scipy
|
requests==2.28.2
|
||||||
uWSGI
|
scipy==1.10.0
|
||||||
ipython
|
uWSGI==2.0.21
|
||||||
|
|
|
@ -11,7 +11,7 @@ import scipy # pylint: disable=unused-import
|
||||||
from matplotlib import pyplot as plt
|
from matplotlib import pyplot as plt
|
||||||
|
|
||||||
from src.db import DatabaseConnect
|
from src.db import DatabaseConnect
|
||||||
from src.helper import get_config, plt_fill
|
from src.helper import chart_fill, get_config, plt_fill
|
||||||
|
|
||||||
FALLBACK_GRAPH = "static/img/fallback.png"
|
FALLBACK_GRAPH = "static/img/fallback.png"
|
||||||
|
|
||||||
|
@ -539,32 +539,24 @@ class YearComparison:
|
||||||
f.write(json_dict)
|
f.write(json_dict)
|
||||||
|
|
||||||
def write_plt(self):
|
def write_plt(self):
|
||||||
""" write year comparison bar chart """
|
"""write year comparison bar chart"""
|
||||||
x = self.axis['x']
|
x = self.axis["x"]
|
||||||
y_1 = self.axis['y_1']
|
y_1 = self.axis["y_1"]
|
||||||
y_2 = self.axis['y_2'].fillna(value=0)
|
y_2 = self.axis["y_2"].fillna(value=0)
|
||||||
# build colors
|
|
||||||
col_y_1 = NightlyPlots.color_colums(y_1)
|
|
||||||
col_y_2 = NightlyPlots.color_colums(y_2)
|
|
||||||
# set ticks
|
# set ticks
|
||||||
y_max = int(np.ceil((max(pd.concat([y_1, y_2])) / 50)) * 50 + 50)
|
y_max = int(np.ceil((max(pd.concat([y_1, y_2])) / 50)) * 50 + 50)
|
||||||
x_indexes = np.arange(len(x))
|
y_ticks = np.arange(0, y_max, step=50)
|
||||||
# build plot
|
# build plot
|
||||||
width = 0.25
|
plt.title("Daily avg AQI values compared to last year", fontsize=15)
|
||||||
plt_title = 'Daily avg AQI values compared to last year'
|
chart_fill(plt, y_ticks)
|
||||||
plt_suptitle = 'left: this year, right: last year'
|
plt.style.use("seaborn")
|
||||||
plt.style.use('seaborn')
|
plt.plot(x, y_1, color="#313131", label="this year")
|
||||||
# write bars
|
plt.plot(
|
||||||
plt.bar(
|
x, y_2, color="#666666", linestyle="dashed", label="last year"
|
||||||
x_indexes - (width / 2) - 0.02, y_1, color=col_y_1, width=width
|
|
||||||
)
|
)
|
||||||
plt.bar(
|
plt.yticks(y_ticks)
|
||||||
x_indexes + (width / 2) + 0.02, y_2, color=col_y_2, width=width
|
plt.legend()
|
||||||
)
|
plt.legend(loc="lower center", bbox_to_anchor=(0.5, -0.02), ncol=2)
|
||||||
plt.title(plt_suptitle, fontsize=15)
|
|
||||||
plt.suptitle(plt_title, fontsize=20, y=0.96)
|
|
||||||
plt.yticks(np.arange(0, y_max, step=50))
|
|
||||||
plt.xticks(ticks=x_indexes, labels=x)
|
|
||||||
plt.tight_layout()
|
plt.tight_layout()
|
||||||
plt.savefig(self.PLT_FILENAME, dpi=300)
|
plt.savefig(self.PLT_FILENAME, dpi=300)
|
||||||
plt.figure()
|
plt.figure()
|
||||||
|
|
|
@ -44,6 +44,54 @@ def plt_fill(plt, x, y):
|
||||||
) # soft
|
) # soft
|
||||||
|
|
||||||
|
|
||||||
|
def chart_fill(plt, y_ticks):
|
||||||
|
"""fill line chart background"""
|
||||||
|
key_map = {
|
||||||
|
0: {
|
||||||
|
"low": 0,
|
||||||
|
"high": 50,
|
||||||
|
"color": "#85a762",
|
||||||
|
"name": "good",
|
||||||
|
},
|
||||||
|
50: {
|
||||||
|
"low": 50,
|
||||||
|
"high": 100,
|
||||||
|
"color": "#d4b93c",
|
||||||
|
"name": "moderate",
|
||||||
|
},
|
||||||
|
100: {
|
||||||
|
"low": 100,
|
||||||
|
"high": 150,
|
||||||
|
"color": "#e96843",
|
||||||
|
"name": "ufsg",
|
||||||
|
},
|
||||||
|
150: {
|
||||||
|
"low": 150,
|
||||||
|
"high": 200,
|
||||||
|
"color": "#d03f3b",
|
||||||
|
"name": "unhealthy",
|
||||||
|
},
|
||||||
|
200: {
|
||||||
|
"low": 200,
|
||||||
|
"high": 300,
|
||||||
|
"color": "#be4173",
|
||||||
|
"name": "vunhealthy",
|
||||||
|
},
|
||||||
|
300: {
|
||||||
|
"low": 300,
|
||||||
|
"high": y_ticks[-1],
|
||||||
|
"color": "#714261",
|
||||||
|
"name": "hazardous",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for tick in y_ticks[0:-1]:
|
||||||
|
match = key_map[tick]
|
||||||
|
plt.axhspan(
|
||||||
|
match["low"], match["high"], facecolor=match["color"], zorder=0
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class Table:
|
class Table:
|
||||||
""" create html table from filename to pass to template """
|
""" create html table from filename to pass to template """
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@
|
||||||
{% block content %}{% endblock %}
|
{% block content %}{% endblock %}
|
||||||
<div class="full-width col_bg">
|
<div class="full-width col_bg">
|
||||||
<div class="col-box">
|
<div class="col-box">
|
||||||
<p>© 2022 | <a href="https://github.com/bbilly1/aqi_monitor" target="_blank">Documentation</a></p>
|
<p>© 2023 | <a href="https://github.com/bbilly1/aqi_monitor" target="_blank">Documentation</a></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
|
|
Loading…
Reference in New Issue