Compare commits
9 Commits
0a177eebe8
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f6e7069449 | ||
|
|
24dd2bfd3a | ||
|
|
03ebbcc1f0 | ||
|
|
9210cbf8a1 | ||
|
|
87ed3c81ae | ||
|
|
4abd6ce5d5 | ||
|
|
870424baa0 | ||
|
|
3481ff7976 | ||
|
|
6904ac30d5 |
@@ -1,312 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 6,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import os\n",
|
|
||||||
"import sys\n",
|
|
||||||
"import json\n",
|
|
||||||
"from pathlib import Path\n",
|
|
||||||
"\n",
|
|
||||||
"import yaml\n",
|
|
||||||
"from rich import print"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"class EmptyClass:\n",
|
|
||||||
" pass\n",
|
|
||||||
"\n",
|
|
||||||
"self = EmptyClass()\n",
|
|
||||||
"self.AD = EmptyClass()\n",
|
|
||||||
"self.AD.app_dir = '/mnt/ad_dev_conf/apps'"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Python parents:\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
"Python parents:\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"> - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/apps/my_repo/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">my_pkg</span>\n",
|
|
||||||
" - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">apps</span>\n",
|
|
||||||
" - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/apps/my_repo/my_pkg/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">my_sub_pkg</span>\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/apps/my_repo/\u001b[0m\u001b[95mmy_pkg\u001b[0m\n",
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/\u001b[0m\u001b[95mapps\u001b[0m\n",
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/apps/my_repo/my_pkg/\u001b[0m\u001b[95mmy_sub_pkg\u001b[0m\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Module parents:\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
"Module parents:\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"> - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">apps</span>\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/\u001b[0m\u001b[95mapps\u001b[0m\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Package parents:\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
"Package parents:\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"> - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/apps/my_repo/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">my_pkg</span>\n",
|
|
||||||
" - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/apps/my_repo/my_pkg/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">my_sub_pkg</span>\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/apps/my_repo/\u001b[0m\u001b[95mmy_pkg\u001b[0m\n",
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/apps/my_repo/my_pkg/\u001b[0m\u001b[95mmy_sub_pkg\u001b[0m\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Top package parents:\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
"Top package parents:\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"> - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/apps/my_repo/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">my_pkg</span>\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/apps/my_repo/\u001b[0m\u001b[95mmy_pkg\u001b[0m\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">Imports\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
"Imports\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"> - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">apps</span>\n",
|
|
||||||
" - <span style=\"color: #800080; text-decoration-color: #800080\">/mnt/ad_dev_conf/apps/</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff\">my_repo</span>\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/\u001b[0m\u001b[95mapps\u001b[0m\n",
|
|
||||||
" - \u001b[35m/mnt/ad_dev_conf/apps/\u001b[0m\u001b[95mmy_repo\u001b[0m\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"base_path = Path(self.AD.app_dir)\n",
|
|
||||||
"\n",
|
|
||||||
"python_file_parents = set(\n",
|
|
||||||
" f.parent.resolve()\n",
|
|
||||||
" for f in base_path.rglob('*.py')\n",
|
|
||||||
")\n",
|
|
||||||
"print('Python parents:')\n",
|
|
||||||
"print('\\n'.join(f' - {p.as_posix()}' for p in python_file_parents))\n",
|
|
||||||
"\n",
|
|
||||||
"module_parents = set(\n",
|
|
||||||
" p for p in python_file_parents\n",
|
|
||||||
" if not (p / '__init__.py').exists()\n",
|
|
||||||
")\n",
|
|
||||||
"print('Module parents:')\n",
|
|
||||||
"print('\\n'.join(f' - {p.as_posix()}' for p in module_parents))\n",
|
|
||||||
"\n",
|
|
||||||
"package_parents = set(\n",
|
|
||||||
" p for p in python_file_parents\n",
|
|
||||||
" if (p / '__init__.py').exists()\n",
|
|
||||||
")\n",
|
|
||||||
"print('Package parents:')\n",
|
|
||||||
"print('\\n'.join(f' - {p.as_posix()}' for p in package_parents))\n",
|
|
||||||
"\n",
|
|
||||||
"top_packages_dirs = set(\n",
|
|
||||||
" p for p in package_parents\n",
|
|
||||||
" if not (p.parent / '__init__.py').exists()\n",
|
|
||||||
")\n",
|
|
||||||
"print('Top package parents:')\n",
|
|
||||||
"print('\\n'.join(f' - {p.as_posix()}' for p in top_packages_dirs))\n",
|
|
||||||
"\n",
|
|
||||||
"import_dirs = module_parents | set(p.parent for p in top_packages_dirs)\n",
|
|
||||||
"print('Imports')\n",
|
|
||||||
"print('\\n'.join(f' - {p.as_posix()}' for p in import_dirs))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 4,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/html": [
|
|
||||||
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">{</span>\n",
|
|
||||||
" <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">PosixPath</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'/mnt/ad_dev_conf/apps/my_repo/my_pkg/__init__.py'</span><span style=\"font-weight: bold\">)</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg'</span>,\n",
|
|
||||||
" <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">PosixPath</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'/mnt/ad_dev_conf/apps/my_repo/my_pkg/motion.py'</span><span style=\"font-weight: bold\">)</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg'</span>,\n",
|
|
||||||
" <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">PosixPath</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'/mnt/ad_dev_conf/apps/my_repo/my_pkg/my_sub_pkg/__init__.py'</span><span style=\"font-weight: bold\">)</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg'</span>,\n",
|
|
||||||
" <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">PosixPath</span><span style=\"font-weight: bold\">(</span><span style=\"color: #008000; text-decoration-color: #008000\">'/mnt/ad_dev_conf/apps/my_repo/my_pkg/my_sub_pkg/hello.py'</span><span style=\"font-weight: bold\">)</span>: <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg'</span>\n",
|
|
||||||
"<span style=\"font-weight: bold\">}</span>\n",
|
|
||||||
"</pre>\n"
|
|
||||||
],
|
|
||||||
"text/plain": [
|
|
||||||
"\u001b[1m{\u001b[0m\n",
|
|
||||||
" \u001b[1;35mPosixPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/mnt/ad_dev_conf/apps/my_repo/my_pkg/__init__.py'\u001b[0m\u001b[1m)\u001b[0m: \u001b[32m'my_pkg'\u001b[0m,\n",
|
|
||||||
" \u001b[1;35mPosixPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/mnt/ad_dev_conf/apps/my_repo/my_pkg/motion.py'\u001b[0m\u001b[1m)\u001b[0m: \u001b[32m'my_pkg'\u001b[0m,\n",
|
|
||||||
" \u001b[1;35mPosixPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/mnt/ad_dev_conf/apps/my_repo/my_pkg/my_sub_pkg/__init__.py'\u001b[0m\u001b[1m)\u001b[0m: \u001b[32m'my_pkg'\u001b[0m,\n",
|
|
||||||
" \u001b[1;35mPosixPath\u001b[0m\u001b[1m(\u001b[0m\u001b[32m'/mnt/ad_dev_conf/apps/my_repo/my_pkg/my_sub_pkg/hello.py'\u001b[0m\u001b[1m)\u001b[0m: \u001b[32m'my_pkg'\u001b[0m\n",
|
|
||||||
"\u001b[1m}\u001b[0m\n"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "display_data"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"association = {}\n",
|
|
||||||
"for dir in top_packages_dirs:\n",
|
|
||||||
" associated_modules = list(dir.rglob('*.py'))\n",
|
|
||||||
" # print('\\n'.join(f' - {p.as_posix()}' for p in associated_modules))\n",
|
|
||||||
" for module_file in associated_modules:\n",
|
|
||||||
" association[module_file] = dir.stem\n",
|
|
||||||
"\n",
|
|
||||||
"print(association)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 15,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"['hello_sub', 'motion']"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 15,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"module_name = 'my_pkg'\n",
|
|
||||||
"\n",
|
|
||||||
"with Path('apps/apps.yaml').open('r') as f:\n",
|
|
||||||
" self.app_config = yaml.load(f, Loader=yaml.SafeLoader)\n",
|
|
||||||
"\n",
|
|
||||||
"self.non_apps = []\n",
|
|
||||||
"\n",
|
|
||||||
"[\n",
|
|
||||||
" app_name\n",
|
|
||||||
" for app_name, app_cfg in self.app_config.items()\n",
|
|
||||||
" if app_cfg['module'].split('.')[0] == module_name\n",
|
|
||||||
"]"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "ad_dev",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.11.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import importlib\n",
|
|
||||||
"from pathlib import Path"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": []
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "ad_dev",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.11.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
14
README.md
14
README.md
@@ -23,8 +23,20 @@ Use with VSCode's debugger using a `launch.json` file.
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"module": "appdaemon",
|
"module": "appdaemon",
|
||||||
"justMyCode": true,
|
"justMyCode": true,
|
||||||
"args": "-c ../conf"
|
"args": "-c ../conf" // Expects the conf directory to be next to the appdaemon one
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Pytest",
|
||||||
|
"type": "debugpy",
|
||||||
|
"request": "launch",
|
||||||
|
"module": "pytest",
|
||||||
|
"justMyCode": true,
|
||||||
|
"args": [
|
||||||
|
"${workspaceFolder}/tests",
|
||||||
|
"--maxfail=1", // Stop after the first failure
|
||||||
|
"-s" // Allow for interactive debugging (pdb)
|
||||||
|
],
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -1,13 +1,24 @@
|
|||||||
appdaemon:
|
appdaemon:
|
||||||
import_method: expert
|
# ffake_ketys: asdfasdf
|
||||||
|
# starttime: '2024-07-14 12:00:00' # YYYY-MM-DD HH:MM:SS
|
||||||
|
uvloop: True
|
||||||
|
use_dictionary_unpacking: True
|
||||||
|
# import_method: expert
|
||||||
# import_paths:
|
# import_paths:
|
||||||
# - /conf/apps/my_repo
|
# - /conf/apps/my_repo
|
||||||
latitude: 0
|
latitude: 0
|
||||||
longitude: 0
|
longitude: 0
|
||||||
elevation: 30
|
elevation: 30
|
||||||
time_zone: America/Chicago
|
time_zone: America/Chicago
|
||||||
|
# check_app_updates_profile: True
|
||||||
|
module_debug:
|
||||||
|
_app_management: DEBUG
|
||||||
|
_callbacks: DEBUG
|
||||||
|
# _events: DEBUG
|
||||||
|
# _threading: DEBUG
|
||||||
|
# mqtt: DEBUG
|
||||||
plugins:
|
plugins:
|
||||||
HASS:
|
hass:
|
||||||
type: hass
|
type: hass
|
||||||
ha_url: http://192.168.1.82:8123
|
ha_url: http://192.168.1.82:8123
|
||||||
token: !secret long_lived_token
|
token: !secret long_lived_token
|
||||||
@@ -16,6 +27,7 @@ appdaemon:
|
|||||||
# namespace: mqtt
|
# namespace: mqtt
|
||||||
# client_host: zigbee.localdomain
|
# client_host: zigbee.localdomain
|
||||||
# client_user: homeassistant
|
# client_user: homeassistant
|
||||||
|
# client_id: test_dev_client
|
||||||
# client_password: !secret mqtt_password
|
# client_password: !secret mqtt_password
|
||||||
# client_topics:
|
# client_topics:
|
||||||
# - zigbee2mqtt/#
|
# - zigbee2mqtt/#
|
||||||
|
|||||||
29
apps/app1/button.py
Normal file
29
apps/app1/button.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import json
|
||||||
|
|
||||||
|
from appdaemon.adapi import ADAPI
|
||||||
|
|
||||||
|
|
||||||
|
class Button(ADAPI):
|
||||||
|
def initialize(self):
|
||||||
|
name = self.args['button']
|
||||||
|
self.handle = self.listen_event(
|
||||||
|
self.handle_button,
|
||||||
|
'MQTT_MESSAGE',
|
||||||
|
topic=f'zigbee2mqtt/{name}',
|
||||||
|
payload=self.payload_filter,
|
||||||
|
)
|
||||||
|
self.log(f"Started MQTT app in namespace '{self._namespace}'")
|
||||||
|
# raise ValueError
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def payload_filter(payload: str):
|
||||||
|
try:
|
||||||
|
return json.loads(payload)['action'] != ''
|
||||||
|
except Exception:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def handle_button(self, event_name, data, **kwargs):
|
||||||
|
data['payload'] = json.loads(data['payload'])
|
||||||
|
# if data['payload']['action'] != '':
|
||||||
|
json_str = json.dumps(data, indent=4)
|
||||||
|
self.logger.info(f'{event_name} callback with\n{json_str}\n{kwargs}')
|
||||||
@@ -1,7 +1,12 @@
|
|||||||
from appdaemon.adapi import ADAPI
|
from appdaemon.adapi import ADAPI
|
||||||
|
|
||||||
|
|
||||||
class Database:
|
class Database(ADAPI):
|
||||||
|
def initialize(self):
|
||||||
|
self.comp = DatabaseComponent(self)
|
||||||
|
self.log('Database with component')
|
||||||
|
|
||||||
|
|
||||||
|
class DatabaseComponent:
|
||||||
def __init__(self, ad: ADAPI) -> None:
|
def __init__(self, ad: ADAPI) -> None:
|
||||||
self.ad = ad
|
self.ad = ad
|
||||||
# self.ad.logger.info(' NEW LOG LINE '.center(50, '='))
|
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ from appdaemon.adapi import ADAPI
|
|||||||
|
|
||||||
|
|
||||||
class Notification:
|
class Notification:
|
||||||
def __init__(self, ad: ADAPI) -> None:
|
def __init__(self, ad: ADAPI, name: str) -> None:
|
||||||
self.ad = ad
|
self.ad = ad
|
||||||
self.ad.logger.info(' NEW LOG LINE '.center(50, '='))
|
self.log = self.ad.logger.info
|
||||||
|
self.log(f'Notification initialized for {name}')
|
||||||
|
# self.ad.logger.info(' NOTIFICATION '.center(50, '-'))
|
||||||
|
|
||||||
def send(self, message: str = "message not specified") -> None:
|
def send(self, message: str = 'message not specified') -> None:
|
||||||
self.ad.log(message, level="DEBUG")
|
self.ad.log(f'NOTIFICATION: {message}', level='DEBUG')
|
||||||
|
|||||||
0
apps/app1/subdir/__init__.py
Normal file
0
apps/app1/subdir/__init__.py
Normal file
@@ -1,6 +1,13 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
from appdaemon.adapi import ADAPI
|
from appdaemon.adapi import ADAPI
|
||||||
|
|
||||||
|
from ..notification import Notification
|
||||||
|
|
||||||
|
|
||||||
class Foo(ADAPI):
|
class Foo(ADAPI):
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.log(f'Initialized from {__file__}')
|
# self.log('FOO')
|
||||||
|
self.log(f'Initialized app from {Path(__file__).relative_to(self.AD.app_dir.parent)}')
|
||||||
|
self.notification = Notification(self.AD, self.name)
|
||||||
|
# self.log(' FOO '.center(50, '*'))
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import appdaemon
|
||||||
|
|
||||||
|
# import app2.database
|
||||||
|
|
||||||
|
from . import database
|
||||||
|
|
||||||
|
# from .database import OtherDatabaseApp
|
||||||
|
# from .database import OtherDatabaseApp as NormalApp
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
from appdaemon.adapi import ADAPI
|
from app1.subdir.foo import Foo
|
||||||
|
|
||||||
class OtherDatabaseApp(ADAPI):
|
|
||||||
|
class OtherDatabaseApp(Foo):
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.log(f'Initialized from {__file__}')
|
super().initialize()
|
||||||
|
self.log('This app inherits from a custom class')
|
||||||
|
# self.log(' CHANGE '.center(50, '-'))
|
||||||
|
|||||||
3
apps/apps.yaml
Normal file
3
apps/apps.yaml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
hello_world:
|
||||||
|
module: hello
|
||||||
|
class: HelloWorld
|
||||||
13
apps/automationlib/automationlib.py
Normal file
13
apps/automationlib/automationlib.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import arrow
|
||||||
|
from appdaemon.adapi import ADAPI
|
||||||
|
|
||||||
|
|
||||||
|
class AutomationLib:
|
||||||
|
"""This is the documentation for AutomationLib"""
|
||||||
|
|
||||||
|
def __init__(self, ad: ADAPI) -> None:
|
||||||
|
self.ad = ad
|
||||||
|
self.ad.log(f"AutomationLib initialised for app '{self.ad.name}'", level='DEBUG')
|
||||||
|
|
||||||
|
def dow(self):
|
||||||
|
return arrow.now().isoweekday()
|
||||||
10
apps/automationlib/automationlib.yaml
Normal file
10
apps/automationlib/automationlib.yaml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
automationlib:
|
||||||
|
module: automationlib
|
||||||
|
global: true
|
||||||
|
|
||||||
|
my_test_app:
|
||||||
|
module: test
|
||||||
|
class: Test
|
||||||
|
log_level: DEBUG
|
||||||
|
dependencies:
|
||||||
|
- automationlib
|
||||||
1
apps/automationlib/requirements.txt
Normal file
1
apps/automationlib/requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
arrow
|
||||||
14
apps/automationlib/test.py
Normal file
14
apps/automationlib/test.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from appdaemon.plugins.hass.hassapi import Hass
|
||||||
|
from automationlib import AutomationLib
|
||||||
|
|
||||||
|
|
||||||
|
class Test(Hass):
|
||||||
|
"""This is the documentation for Test"""
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
"""."""
|
||||||
|
|
||||||
|
self.lib = AutomationLib(self)
|
||||||
|
self.log('-' * 72)
|
||||||
|
self.log(f'Day of the week: {self.lib.dow()}')
|
||||||
|
self.log('-' * 72)
|
||||||
6
apps/button.yaml
Normal file
6
apps/button.yaml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
button_test:
|
||||||
|
module: app1.button
|
||||||
|
class: Button
|
||||||
|
button: Living Room Button
|
||||||
|
dependencies:
|
||||||
|
- hello_world
|
||||||
@@ -1,11 +1,25 @@
|
|||||||
# App1:
|
App1:
|
||||||
# module: app1.database
|
module: app1.database
|
||||||
# class: DatabaseApp
|
class: Database
|
||||||
|
other_kwargs: value
|
||||||
App2:
|
dependencies: Sound
|
||||||
module: app2.database
|
|
||||||
class: OtherDatabaseApp
|
|
||||||
|
|
||||||
App1Foo:
|
App1Foo:
|
||||||
module: app1.subdir.foo
|
module: app1.subdir.foo
|
||||||
class: Foo
|
class: Foo
|
||||||
|
# dependencies:
|
||||||
|
# - companion_app
|
||||||
|
|
||||||
|
App2:
|
||||||
|
module: app2.database
|
||||||
|
class: OtherDatabaseApp
|
||||||
|
dependencies:
|
||||||
|
- App1
|
||||||
|
- App1Foo
|
||||||
|
- globals
|
||||||
|
|
||||||
|
App3:
|
||||||
|
module: app2.database
|
||||||
|
class: OtherDatabaseApp
|
||||||
|
dependencies:
|
||||||
|
- App2
|
||||||
|
|||||||
0
apps/family/__init__.py
Normal file
0
apps/family/__init__.py
Normal file
10
apps/family/child.py
Normal file
10
apps/family/child.py
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
from appdaemon.adapi import ADAPI
|
||||||
|
|
||||||
|
from .utils import UTILS_VALS
|
||||||
|
|
||||||
|
|
||||||
|
raise ImportError('Fake import error')
|
||||||
|
|
||||||
|
class Child(ADAPI):
|
||||||
|
def initialize(self):
|
||||||
|
self.log(f'Initialized child with: {UTILS_VALS}')
|
||||||
7
apps/family/family.yaml
Normal file
7
apps/family/family.yaml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
parent:
|
||||||
|
module: family.parent
|
||||||
|
class: Parent
|
||||||
|
|
||||||
|
child:
|
||||||
|
module: family.child
|
||||||
|
class: Child
|
||||||
8
apps/family/parent.py
Normal file
8
apps/family/parent.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from appdaemon.adapi import ADAPI
|
||||||
|
|
||||||
|
from .utils import UTILS_VALS
|
||||||
|
|
||||||
|
|
||||||
|
class Parent(ADAPI):
|
||||||
|
def initialize(self):
|
||||||
|
self.log(f'Initialized parent with: {UTILS_VALS}')
|
||||||
0
apps/family/relatives/__init__.py
Normal file
0
apps/family/relatives/__init__.py
Normal file
1
apps/family/relatives/city.py
Normal file
1
apps/family/relatives/city.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
OTHER_CITY = 'NYC again'
|
||||||
3
apps/family/utils.py
Normal file
3
apps/family/utils.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
from .relatives.city import OTHER_CITY
|
||||||
|
|
||||||
|
UTILS_VALS = 100, 600
|
||||||
@@ -1,6 +1,10 @@
|
|||||||
globals:
|
globals:
|
||||||
module: globals
|
module: globals
|
||||||
global: true
|
global: true
|
||||||
companion_app:
|
|
||||||
module: app1.notification
|
# companion_app:
|
||||||
global: true
|
# module: app1.notification
|
||||||
|
# global: true
|
||||||
|
|
||||||
|
global_modules:
|
||||||
|
- hello
|
||||||
|
|||||||
@@ -1,25 +1,8 @@
|
|||||||
import logging
|
from pathlib import Path
|
||||||
import logging.config
|
|
||||||
|
|
||||||
from appdaemon.adapi import ADAPI
|
from appdaemon.adapi import ADAPI
|
||||||
|
|
||||||
|
|
||||||
class HelloWorld(ADAPI):
|
class HelloWorld(ADAPI):
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.log(f'Initialized app from {__file__}')
|
self.log(f'Initialized app from {Path(__file__).relative_to(Path(self.AD.app_dir).parent)}')
|
||||||
|
|
||||||
# logging.config.dictConfig(
|
|
||||||
# {
|
|
||||||
# 'version': 1,
|
|
||||||
# 'disable_existing_loggers': False,
|
|
||||||
# 'formatters': {'basic': {'style': '{', 'format': '{message}'}},
|
|
||||||
# 'handlers': {'rich': {'()': 'rich.logging.RichHandler'}},
|
|
||||||
# 'loggers': {
|
|
||||||
# 'AppDaemon._app_management': {
|
|
||||||
# 'level': 'DEBUG',
|
|
||||||
# 'propagate': False,
|
|
||||||
# 'handlers': ['rich'],
|
|
||||||
# }
|
|
||||||
# },
|
|
||||||
# }
|
|
||||||
# )
|
|
||||||
|
|||||||
667
apps/my_repo/src/Dependencies.ipynb
Normal file
667
apps/my_repo/src/Dependencies.ipynb
Normal file
@@ -0,0 +1,667 @@
|
|||||||
|
{
|
||||||
|
"cells": [
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 1,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import ast\n",
|
||||||
|
"import importlib\n",
|
||||||
|
"import sys\n",
|
||||||
|
"from pathlib import Path\n",
|
||||||
|
"from types import ModuleType\n",
|
||||||
|
"from typing import Dict, Iterable, Iterator, Mapping, Set, Tuple\n",
|
||||||
|
"\n",
|
||||||
|
"from rich import print"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 2,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"from appdaemon.dependency import (\n",
|
||||||
|
" Graph,\n",
|
||||||
|
" find_all_dependents,\n",
|
||||||
|
" get_all_nodes,\n",
|
||||||
|
" get_dependency_graph,\n",
|
||||||
|
" get_file_deps,\n",
|
||||||
|
" get_full_module_name,\n",
|
||||||
|
" resolve_relative_import,\n",
|
||||||
|
" reverse_graph,\n",
|
||||||
|
" topo_sort,\n",
|
||||||
|
")\n",
|
||||||
|
"from appdaemon.models.internal.file_check import FileCheck"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Logging"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 3,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"import logging.config\n",
|
||||||
|
"\n",
|
||||||
|
"from rich.console import Console\n",
|
||||||
|
"from rich.highlighter import NullHighlighter\n",
|
||||||
|
"\n",
|
||||||
|
"console = Console()\n",
|
||||||
|
"\n",
|
||||||
|
"logging.config.dictConfig(\n",
|
||||||
|
" {\n",
|
||||||
|
" 'version': 1,\n",
|
||||||
|
" 'disable_existing_loggers': False,\n",
|
||||||
|
" 'formatters': {'basic': {'style': '{', 'format': '{message}'}},\n",
|
||||||
|
" 'handlers': {\n",
|
||||||
|
" 'rich': {\n",
|
||||||
|
" '()': 'rich.logging.RichHandler',\n",
|
||||||
|
" 'formatter': 'basic',\n",
|
||||||
|
" 'console': console,\n",
|
||||||
|
" 'highlighter': NullHighlighter(),\n",
|
||||||
|
" 'markup': True\n",
|
||||||
|
" }\n",
|
||||||
|
" },\n",
|
||||||
|
" 'root': {'level': 'DEBUG', 'handlers': ['rich']},\n",
|
||||||
|
" }\n",
|
||||||
|
")\n",
|
||||||
|
"\n",
|
||||||
|
"logger = logging.getLogger()"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## App Load Example\n",
|
||||||
|
"\n",
|
||||||
|
"Example of using importlib to (re)load an app class from a module."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 4,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"change\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"><</span><span style=\"color: #ff00ff; text-decoration-color: #ff00ff; font-weight: bold\">class</span><span style=\"color: #000000; text-decoration-color: #000000\"> </span><span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.deep_pkg.deep_mod.Deep'</span><span style=\"font-weight: bold\">></span>\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"\u001b[1m<\u001b[0m\u001b[1;95mclass\u001b[0m\u001b[39m \u001b[0m\u001b[32m'my_pkg.my_sub_pkg.deep_pkg.deep_mod.Deep'\u001b[0m\u001b[1m>\u001b[0m\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"# apps_path = '/home/john/conf/apps'\n",
|
||||||
|
"# module_name = 'app2'\n",
|
||||||
|
"# class_name = 'NormalApp'\n",
|
||||||
|
"\n",
|
||||||
|
"apps_path = '/home/john/conf/apps/my_repo/src'\n",
|
||||||
|
"module_name = 'my_pkg.my_sub_pkg.deep_pkg'\n",
|
||||||
|
"class_name = 'Deep'\n",
|
||||||
|
"\n",
|
||||||
|
"if apps_path not in sys.path:\n",
|
||||||
|
" sys.path.insert(0, apps_path)\n",
|
||||||
|
"\n",
|
||||||
|
"if mod := sys.modules.get(module_name):\n",
|
||||||
|
" importlib.reload(mod)\n",
|
||||||
|
"else:\n",
|
||||||
|
" mod = importlib.import_module(module_name)\n",
|
||||||
|
"\n",
|
||||||
|
"class_def = getattr(mod, class_name)\n",
|
||||||
|
"print(class_def)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 5,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"['my_pkg',\n",
|
||||||
|
" 'my_pkg.foo',\n",
|
||||||
|
" 'my_pkg.my_sub_pkg',\n",
|
||||||
|
" 'my_pkg.my_sub_pkg.bar',\n",
|
||||||
|
" 'my_pkg.my_sub_pkg.deep_pkg',\n",
|
||||||
|
" 'my_pkg.my_sub_pkg.deep_pkg.deep_mod']"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 5,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"pkgs = sorted(name for name in sys.modules.keys() if name.startswith('my'))\n",
|
||||||
|
"pkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## File Mapping\n",
|
||||||
|
"\n",
|
||||||
|
"Mapping each file to the package string it will be imported from, so it can be retrieved from `sys.modules`\n",
|
||||||
|
"\n",
|
||||||
|
"Flow\n",
|
||||||
|
"\n",
|
||||||
|
"- List of changed files\n",
|
||||||
|
"- Package associated with each file\n",
|
||||||
|
"- Packages that each file depends on"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 6,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"app_dir = Path('/home/john/conf/apps')\n",
|
||||||
|
"# files_to_modules = paths_to_modules(app_dir)\n",
|
||||||
|
"# print(files_to_modules)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Dependencies\n",
|
||||||
|
"\n",
|
||||||
|
"Find which modules each module depends on.\n",
|
||||||
|
"\n",
|
||||||
|
"```python\n",
|
||||||
|
"deps = {\n",
|
||||||
|
" 'A': {'B', 'C'},\n",
|
||||||
|
" 'B': {'C'},\n",
|
||||||
|
" 'C': {'D'},\n",
|
||||||
|
" 'D': set()\n",
|
||||||
|
"}\n",
|
||||||
|
"```\n",
|
||||||
|
"\n",
|
||||||
|
"`A` depends on `B` and `C`.\n",
|
||||||
|
"\n",
|
||||||
|
"If `D` needs to get reloaded, what else does too?"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 7,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"color: #00ff00; text-decoration-color: #00ff00; font-style: italic\">True</span>\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"\u001b[3;92mTrue\u001b[0m\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/plain": [
|
||||||
|
"{'C': {'A', 'B'}, 'D': {'C'}, 'B': {'A'}, 'A': set()}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"execution_count": 7,
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "execute_result"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"deps = {'A': {'B', 'C'}, 'B': {'C'}, 'C': {'D'}, 'D': set()}\n",
|
||||||
|
"\n",
|
||||||
|
"reversable = deps == reverse_graph(reverse_graph(deps))\n",
|
||||||
|
"print(reversable)\n",
|
||||||
|
"\n",
|
||||||
|
"reverse_graph(deps)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 8,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">{</span>\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'hello'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'pathlib'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'logging.config'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adapi'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'logging'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'globals'</span>: <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">set</span><span style=\"font-weight: bold\">()</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.foo'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.bar'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.foo'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'pathlib'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adbase'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.bar'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'pathlib'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adbase'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.bar'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.baz'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'pathlib'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adbase'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.deep_pkg.deep_mod'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'pathlib'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adbase'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.deep_pkg'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.foo'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.deep_pkg.deep_mod'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.bar'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'app1.notification'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adapi'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'app1'</span>: <span style=\"color: #800080; text-decoration-color: #800080; font-weight: bold\">set</span><span style=\"font-weight: bold\">()</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'app1.database'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adapi'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'foo'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adapi'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'test'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'app1.notification'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adbase'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'app2'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'app2.database'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon'</span><span style=\"font-weight: bold\">}</span>,\n",
|
||||||
|
" <span style=\"color: #008000; text-decoration-color: #008000\">'app2.database'</span>: <span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'appdaemon.adapi'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'app1.subdir.foo'</span><span style=\"font-weight: bold\">}</span>\n",
|
||||||
|
"<span style=\"font-weight: bold\">}</span>\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"\u001b[1m{\u001b[0m\n",
|
||||||
|
" \u001b[32m'hello'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'pathlib'\u001b[0m, \u001b[32m'logging.config'\u001b[0m, \u001b[32m'appdaemon.adapi'\u001b[0m, \u001b[32m'logging'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'globals'\u001b[0m: \u001b[1;35mset\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m,\n",
|
||||||
|
" \u001b[32m'my_pkg'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'my_pkg.foo'\u001b[0m, \u001b[32m'my_pkg.my_sub_pkg.bar'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'my_pkg.foo'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'pathlib'\u001b[0m, \u001b[32m'appdaemon.adbase'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'my_pkg.my_sub_pkg.bar'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'pathlib'\u001b[0m, \u001b[32m'appdaemon.adbase'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'my_pkg.my_sub_pkg'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'my_pkg.my_sub_pkg.bar'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'my_pkg.my_sub_pkg.baz'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'pathlib'\u001b[0m, \u001b[32m'appdaemon.adbase'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'my_pkg.my_sub_pkg.deep_pkg.deep_mod'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'pathlib'\u001b[0m, \u001b[32m'appdaemon.adbase'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'my_pkg.my_sub_pkg.deep_pkg'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'my_pkg.foo'\u001b[0m, \u001b[32m'my_pkg.my_sub_pkg.deep_pkg.deep_mod'\u001b[0m, \u001b[32m'my_pkg.my_sub_pkg.bar'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'app1.notification'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'appdaemon.adapi'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'app1'\u001b[0m: \u001b[1;35mset\u001b[0m\u001b[1m(\u001b[0m\u001b[1m)\u001b[0m,\n",
|
||||||
|
" \u001b[32m'app1.database'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'appdaemon.adapi'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'foo'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'appdaemon.adapi'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'test'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'app1.notification'\u001b[0m, \u001b[32m'appdaemon.adbase'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'app2'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'app2.database'\u001b[0m, \u001b[32m'appdaemon'\u001b[0m\u001b[1m}\u001b[0m,\n",
|
||||||
|
" \u001b[32m'app2.database'\u001b[0m: \u001b[1m{\u001b[0m\u001b[32m'appdaemon.adapi'\u001b[0m, \u001b[32m'app1.subdir.foo'\u001b[0m\u001b[1m}\u001b[0m\n",
|
||||||
|
"\u001b[1m}\u001b[0m\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"module_dependencies = get_dependency_graph(app_dir.rglob('*.py'))\n",
|
||||||
|
"print(module_dependencies)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 9,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">{</span><span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.deep_pkg.deep_mod'</span>, <span style=\"color: #008000; text-decoration-color: #008000\">'my_pkg.my_sub_pkg.deep_pkg'</span><span style=\"font-weight: bold\">}</span>\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"\u001b[1m{\u001b[0m\u001b[32m'my_pkg.my_sub_pkg.deep_pkg.deep_mod'\u001b[0m, \u001b[32m'my_pkg.my_sub_pkg.deep_pkg'\u001b[0m\u001b[1m}\u001b[0m\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"files = [\n",
|
||||||
|
" Path('/home/john/conf/apps/my_repo/src/my_pkg/my_sub_pkg/deep_pkg/__init__.py'),\n",
|
||||||
|
" Path('/home/john/conf/apps/my_repo/src/my_pkg/my_sub_pkg/deep_pkg/deep_mod.py'),\n",
|
||||||
|
"]\n",
|
||||||
|
"\n",
|
||||||
|
"changed_pkg = set(get_full_module_name(f) for f in files)\n",
|
||||||
|
"reversed_deps = reverse_graph(module_dependencies)\n",
|
||||||
|
"dependents = find_all_dependents(changed_pkg, reversed_deps)\n",
|
||||||
|
"to_load = changed_pkg | dependents\n",
|
||||||
|
"print(to_load)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 11,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--------------------------------------------------\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"--------------------------------------------------\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">from <span style=\"color: #808000; text-decoration-color: #808000\">...</span>foo import Foo\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"from \u001b[33m...\u001b[0mfoo import Foo\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">my_pkg.foo\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"my_pkg.foo\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--------------------------------------------------\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"--------------------------------------------------\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">from ..bar import Bar\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"from ..bar import Bar\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">my_pkg.my_sub_pkg.bar\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"my_pkg.my_sub_pkg.bar\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--------------------------------------------------\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"--------------------------------------------------\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">from . import deep_mod\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"from . import deep_mod\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">my_pkg.my_sub_pkg.deep_pkg\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"my_pkg.my_sub_pkg.deep_pkg\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--------------------------------------------------\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"--------------------------------------------------\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">from .. import bar\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"from .. import bar\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">my_pkg.my_sub_pkg\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"my_pkg.my_sub_pkg\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">--------------------------------------------------\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"--------------------------------------------------\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">from .deep_mod import Deep\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"from .deep_mod import Deep\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"data": {
|
||||||
|
"text/html": [
|
||||||
|
"<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">my_pkg.my_sub_pkg.deep_pkg.deep_mod\n",
|
||||||
|
"</pre>\n"
|
||||||
|
],
|
||||||
|
"text/plain": [
|
||||||
|
"my_pkg.my_sub_pkg.deep_pkg.deep_mod\n"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"metadata": {},
|
||||||
|
"output_type": "display_data"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"def test_rel_imports(file: Path):\n",
|
||||||
|
" with file.open('r') as f:\n",
|
||||||
|
" file_content = f.read()\n",
|
||||||
|
" \n",
|
||||||
|
" lines = file_content.splitlines()\n",
|
||||||
|
"\n",
|
||||||
|
" tree = ast.parse(file_content, filename=file)\n",
|
||||||
|
" for node in ast.walk(tree):\n",
|
||||||
|
" if isinstance(node, ast.ImportFrom):\n",
|
||||||
|
" abs_module = resolve_relative_import(node, file)\n",
|
||||||
|
" print('-' * 50)\n",
|
||||||
|
" print(lines[node.lineno-1])\n",
|
||||||
|
" print(abs_module)\n",
|
||||||
|
"\n",
|
||||||
|
"test_rel_imports(files[0])"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### Partial Dependency Graph\n",
|
||||||
|
"\n",
|
||||||
|
"This is an example of generating the dependency graph using an iterable of file Paths."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"p = Path('/home/john/conf/apps/my_repo/src/my_pkg/my_sub_pkg')\n",
|
||||||
|
"files = p.rglob('*.py')\n",
|
||||||
|
"\n",
|
||||||
|
"dep_graph = {get_full_module_name(f): get_file_deps(f) for f in files} \n",
|
||||||
|
"dep_graph"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"reload_deps = {m: module_dependencies[m] for m in to_load}\n",
|
||||||
|
"print(reload_deps)\n",
|
||||||
|
"topo_sort(reload_deps)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"files = [\n",
|
||||||
|
" Path('/home/john/conf/apps/my_repo/src/my_pkg/my_sub_pkg/deep_pkg/__init__.py'),\n",
|
||||||
|
" Path('/home/john/conf/apps/my_repo/src/my_pkg/my_sub_pkg/deep_pkg/deep_mod.py'),\n",
|
||||||
|
"]\n",
|
||||||
|
"\n",
|
||||||
|
"for f in files:\n",
|
||||||
|
" mod_name = get_file_deps(f)\n",
|
||||||
|
" print(mod_name)\n",
|
||||||
|
" break\n",
|
||||||
|
"\n",
|
||||||
|
"with f.open(\"r\") as file:\n",
|
||||||
|
" file_content = file.read()\n",
|
||||||
|
"tree = ast.parse(file_content, filename=f)\n",
|
||||||
|
"for node in ast.walk(tree):\n",
|
||||||
|
" if isinstance(node, ast.ImportFrom):\n",
|
||||||
|
" print(node.level, node.module)\n",
|
||||||
|
" if node.level:\n",
|
||||||
|
" abs_module = resolve_relative_import(node, f)\n",
|
||||||
|
" if not node.module:\n",
|
||||||
|
" abs_module += f'.{node.names[0].name}'\n",
|
||||||
|
" print(abs_module)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## File Checking"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": [
|
||||||
|
"files = app_dir.rglob('*.py')\n",
|
||||||
|
"\n",
|
||||||
|
"fc = FileCheck.from_paths(files)\n",
|
||||||
|
"print('\\n'.join(f'{f.relative_to(app_dir.parent)}' for f in fc.new))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": null,
|
||||||
|
"metadata": {},
|
||||||
|
"outputs": [],
|
||||||
|
"source": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"metadata": {
|
||||||
|
"kernelspec": {
|
||||||
|
"display_name": "appdaemon",
|
||||||
|
"language": "python",
|
||||||
|
"name": "python3"
|
||||||
|
},
|
||||||
|
"language_info": {
|
||||||
|
"codemirror_mode": {
|
||||||
|
"name": "ipython",
|
||||||
|
"version": 3
|
||||||
|
},
|
||||||
|
"file_extension": ".py",
|
||||||
|
"mimetype": "text/x-python",
|
||||||
|
"name": "python",
|
||||||
|
"nbconvert_exporter": "python",
|
||||||
|
"pygments_lexer": "ipython3",
|
||||||
|
"version": "3.11.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
||||||
@@ -2,17 +2,11 @@ from pathlib import Path
|
|||||||
|
|
||||||
from appdaemon.adbase import ADBase
|
from appdaemon.adbase import ADBase
|
||||||
|
|
||||||
filename = Path(__file__).name
|
|
||||||
# print(f' Importing {filename} '.center(50, '-'))
|
|
||||||
|
|
||||||
class Foo(ADBase):
|
class Foo(ADBase):
|
||||||
changes: bool = True
|
changes: bool = True
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.adapi = self.get_ad_api()
|
self.adapi = self.get_ad_api()
|
||||||
|
self.adapi.log(f'Initialized app from {Path(__file__).relative_to(self.AD.app_dir.parent)}')
|
||||||
self.adapi.log(f'Initialized app from {filename} new line changes: {self.changes}')
|
self.adapi.log(f'new line changes: {self.changes}')
|
||||||
# self.adapi.log(f'New log line: {self.changes}')
|
|
||||||
# self.adapi.log(f'Even newer log line: {self.changes}')
|
|
||||||
|
|
||||||
# print(f' Foo.changes = {Foo.changes} '.center(50, '-'))
|
|
||||||
|
|||||||
@@ -8,5 +8,5 @@ filename = Path(__file__).name
|
|||||||
class Bar(ADBase):
|
class Bar(ADBase):
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.adapi = self.get_ad_api()
|
self.adapi = self.get_ad_api()
|
||||||
self.adapi.log(f'Initialized app from {filename}')
|
self.log = self.adapi.log
|
||||||
# self.adapi.log(f'CHANGED')
|
self.log(f'Initialized app from {filename}')
|
||||||
|
|||||||
@@ -2,9 +2,12 @@ from pathlib import Path
|
|||||||
|
|
||||||
from appdaemon.adbase import ADBase
|
from appdaemon.adbase import ADBase
|
||||||
|
|
||||||
|
# from . import deep_pkg
|
||||||
|
|
||||||
filename = Path(__file__).name
|
filename = Path(__file__).name
|
||||||
# print(f' Importing {filename} '.center(50, '-'))
|
# print(f' Importing {filename} '.center(50, '-'))
|
||||||
|
|
||||||
|
|
||||||
class Baz(ADBase):
|
class Baz(ADBase):
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
self.adapi = self.get_ad_api()
|
self.adapi = self.get_ad_api()
|
||||||
|
|||||||
7
apps/my_repo/src/my_pkg/my_sub_pkg/deep_pkg/__init__.py
Normal file
7
apps/my_repo/src/my_pkg/my_sub_pkg/deep_pkg/__init__.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
from ...foo import Foo
|
||||||
|
from ..bar import Bar
|
||||||
|
from . import deep_mod
|
||||||
|
from .. import bar
|
||||||
|
from .deep_mod import Deep
|
||||||
|
|
||||||
|
# print(Deep.version)
|
||||||
13
apps/my_repo/src/my_pkg/my_sub_pkg/deep_pkg/deep_mod.py
Normal file
13
apps/my_repo/src/my_pkg/my_sub_pkg/deep_pkg/deep_mod.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from appdaemon.adbase import ADBase
|
||||||
|
|
||||||
|
filename = Path(__file__).name
|
||||||
|
|
||||||
|
class Deep(ADBase):
|
||||||
|
version = 'change'
|
||||||
|
|
||||||
|
def initialize(self):
|
||||||
|
self.adapi = self.get_ad_api()
|
||||||
|
self.adapi.log(f'Initialized app from {filename}')
|
||||||
|
# self.adapi.log(f'CHANGED')
|
||||||
@@ -1,15 +1,11 @@
|
|||||||
Foo:
|
Repo-Foo:
|
||||||
module: my_pkg
|
module: my_pkg
|
||||||
class: Foo
|
class: Foo
|
||||||
|
|
||||||
Bar:
|
Repo-Bar:
|
||||||
module: my_pkg.my_sub_pkg
|
module: my_pkg.my_sub_pkg
|
||||||
class: Bar
|
class: Bar
|
||||||
|
|
||||||
Baz:
|
Repo-Baz:
|
||||||
module: my_pkg.my_sub_pkg.baz
|
module: my_pkg.my_sub_pkg.baz
|
||||||
class: Baz
|
class: Baz
|
||||||
|
|
||||||
Hello:
|
|
||||||
module: hello
|
|
||||||
class: HelloWorld
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
rich
|
rich
|
||||||
anyio
|
anyio
|
||||||
pydantic
|
pydantic
|
||||||
|
# arrow
|
||||||
18
apps/sequence.yaml
Normal file
18
apps/sequence.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
sequence:
|
||||||
|
office_on:
|
||||||
|
name: Office On
|
||||||
|
namespace: hass
|
||||||
|
steps:
|
||||||
|
- homeassistant/turn_on:
|
||||||
|
entity_id: light.office_1
|
||||||
|
brightness: 254
|
||||||
|
- homeassistant/turn_on:
|
||||||
|
entity_id: light.office_2
|
||||||
|
brightness: 254
|
||||||
|
office_off:
|
||||||
|
name: Office Off
|
||||||
|
steps:
|
||||||
|
- homeassistant/turn_off:
|
||||||
|
entity_id: light.office_1
|
||||||
|
- homeassistant/turn_off:
|
||||||
|
entity_id: light.office_2
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
|
Hello:
|
||||||
|
module: hello
|
||||||
|
class: HelloWorld
|
||||||
|
|
||||||
Hello2:
|
Hello2:
|
||||||
module: hello
|
module: hello
|
||||||
class: HelloWorld
|
class: HelloWorld
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
from app1.notification import Notification
|
|
||||||
from appdaemon.adbase import ADBase
|
|
||||||
|
|
||||||
|
|
||||||
class Test(ADBase):
|
|
||||||
def initialize(self):
|
|
||||||
self.adapi = self.get_ad_api()
|
|
||||||
self.notify = Notification(self.adapi)
|
|
||||||
self.notify.send("Test message from Test2 app.")
|
|
||||||
@@ -1,5 +1,11 @@
|
|||||||
test:
|
test_notifier:
|
||||||
module: test
|
# module: test_notify
|
||||||
class: Test
|
# class: TestNotifier
|
||||||
|
module: variant
|
||||||
|
class: Variant
|
||||||
log_level: DEBUG
|
log_level: DEBUG
|
||||||
dependencies: companion_app
|
# dependencies: companion_app
|
||||||
|
|
||||||
|
TestApp:
|
||||||
|
module: test_notify
|
||||||
|
class: TestNotifier
|
||||||
|
|||||||
11
apps/test/test_notify.py
Normal file
11
apps/test/test_notify.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from app1.notification import Notification
|
||||||
|
from appdaemon.adbase import ADBase
|
||||||
|
|
||||||
|
|
||||||
|
class TestNotifier(ADBase):
|
||||||
|
def initialize(self):
|
||||||
|
self.adapi = self.get_ad_api()
|
||||||
|
self.log = self.adapi.log
|
||||||
|
self.log(f'Initialized test notifier class: {self.__class__.__name__}')
|
||||||
|
self.notify = Notification(self.adapi, self.name)
|
||||||
|
self.notify.send('Some notifications')
|
||||||
8
apps/test/variant.py
Normal file
8
apps/test/variant.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
from test_notify import TestNotifier
|
||||||
|
from appdaemon.adapi import ADAPI
|
||||||
|
|
||||||
|
class Variant(TestNotifier, ADAPI):
|
||||||
|
def initialize(self):
|
||||||
|
super().initialize()
|
||||||
|
self.log('Variant of the TestNotifier')
|
||||||
|
# self.log(' VARIANT '.center(50, '*'))
|
||||||
@@ -2,6 +2,7 @@ services:
|
|||||||
appdaemon:
|
appdaemon:
|
||||||
container_name: appdaemon_dev
|
container_name: appdaemon_dev
|
||||||
image: appdaemon:local-dev
|
image: appdaemon:local-dev
|
||||||
|
# image: acockburn/appdaemon:dev
|
||||||
volumes:
|
volumes:
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
- /etc/timezone:/etc/timezone:ro
|
- /etc/timezone:/etc/timezone:ro
|
||||||
|
|||||||
144
modules.ipynb
144
modules.ipynb
@@ -1,144 +0,0 @@
|
|||||||
{
|
|
||||||
"cells": [
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 1,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"import importlib\n",
|
|
||||||
"\n",
|
|
||||||
"import pathlib\n",
|
|
||||||
"from types import ModuleType\n",
|
|
||||||
"from typing import List\n",
|
|
||||||
"from pathlib import Path\n",
|
|
||||||
"\n",
|
|
||||||
"from IPython.lib import deepreload"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 2,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"=============== Importing my_pkg ===============\n",
|
|
||||||
"-------------- Importing motion.py ---------------\n",
|
|
||||||
"===================== Done =====================\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"import sys\n",
|
|
||||||
"\n",
|
|
||||||
"sys.path.insert(0, Path('apps/my_repo').resolve().as_posix())\n",
|
|
||||||
"\n",
|
|
||||||
"import my_pkg"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"data": {
|
|
||||||
"text/plain": [
|
|
||||||
"['importlib._abc',\n",
|
|
||||||
" 'importlib._bootstrap',\n",
|
|
||||||
" 'importlib._bootstrap_external',\n",
|
|
||||||
" 'importlib._imp',\n",
|
|
||||||
" 'importlib.abc',\n",
|
|
||||||
" 'importlib.machinery',\n",
|
|
||||||
" 'importlib.metadata',\n",
|
|
||||||
" 'importlib.resources',\n",
|
|
||||||
" 'importlib.sys',\n",
|
|
||||||
" 'importlib.util',\n",
|
|
||||||
" 'importlib.warnings']"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"execution_count": 3,
|
|
||||||
"metadata": {},
|
|
||||||
"output_type": "execute_result"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def recursive_modules(module_obj: ModuleType) -> List[str]:\n",
|
|
||||||
" sub_modules = [\n",
|
|
||||||
" f'{module_obj.__name__}.{name}' for name in dir(module_obj)\n",
|
|
||||||
" if isinstance(getattr(module_obj, name), ModuleType)\n",
|
|
||||||
" ]\n",
|
|
||||||
" return sub_modules\n",
|
|
||||||
"\n",
|
|
||||||
"recursive_modules(importlib)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 10,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"[<module 'my_pkg' from '/home/john/conf/apps/my_repo/my_pkg/__init__.py'>, <module 'my_pkg.motion' from '/home/john/conf/apps/my_repo/my_pkg/motion.py'>, <module 'my_pkg.my_sub_pkg' from '/home/john/conf/apps/my_repo/my_pkg/my_sub_pkg/__init__.py'>, <module 'my_pkg.my_sub_pkg.hello' from '/home/john/conf/apps/my_repo/my_pkg/my_sub_pkg/hello.py'>]\n",
|
|
||||||
"=============== Importing my_pkg ===============\n",
|
|
||||||
"===================== Done =====================\n",
|
|
||||||
"-------------- Importing motion.py ---------------\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"def recursive_modules(module: ModuleType):\n",
|
|
||||||
" for name in dir(module):\n",
|
|
||||||
" sub_mod = getattr(module, name)\n",
|
|
||||||
" if isinstance(sub_mod, ModuleType) and sub_mod.__name__.startswith(module.__name__):\n",
|
|
||||||
" yield from recursive_modules(sub_mod)\n",
|
|
||||||
" yield module\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"def reload_package(pkg: ModuleType):\n",
|
|
||||||
" modules = sorted(recursive_modules(pkg), key=lambda m: m.__name__)\n",
|
|
||||||
" for mod in modules:\n",
|
|
||||||
" importlib.reload(mod)\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"reload_package(my_pkg)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": null,
|
|
||||||
"metadata": {},
|
|
||||||
"outputs": [],
|
|
||||||
"source": [
|
|
||||||
"importlib.import_module(name)"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"metadata": {
|
|
||||||
"kernelspec": {
|
|
||||||
"display_name": "appdaemon",
|
|
||||||
"language": "python",
|
|
||||||
"name": "python3"
|
|
||||||
},
|
|
||||||
"language_info": {
|
|
||||||
"codemirror_mode": {
|
|
||||||
"name": "ipython",
|
|
||||||
"version": 3
|
|
||||||
},
|
|
||||||
"file_extension": ".py",
|
|
||||||
"mimetype": "text/x-python",
|
|
||||||
"name": "python",
|
|
||||||
"nbconvert_exporter": "python",
|
|
||||||
"pygments_lexer": "ipython3",
|
|
||||||
"version": "3.11.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nbformat": 4,
|
|
||||||
"nbformat_minor": 2
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user