Skip to content

Commit

Permalink
Merge pull request #21 from MohammadrezaAmani/inui-1.0.0.1-query
Browse files Browse the repository at this point in the history
fit(CLI): add cli tools to code.
  • Loading branch information
MohammadrezaAmani authored Nov 23, 2024
2 parents a1330e5 + 73dafd7 commit 87a07a5
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 95 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pipy_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- name: Set up Python 3.12
uses: actions/setup-python@v3
with:
python-version: '3.12'
python-version: "3.12"

- name: Upgrade pip and install tools
run: |
Expand Down
Binary file modified inui/.DS_Store
Binary file not shown.
20 changes: 20 additions & 0 deletions inui/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import logging
import importlib

logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)


def build(module, variable, out: str | None, _print: bool = True):
lib = importlib.import_module(module)

rendered = str(getattr(lib, variable))
if out:
with open(out, "w", encoding="utf-8") as f:
f.write(rendered)
return rendered
else:
if _print:
print(rendered)
return rendered
146 changes: 146 additions & 0 deletions inui/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import argparse
import sys
from inui.hotreload import hot_reload
from inui import build
from inui.toinui import convert
import logging

logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
COMMANDS = {
"run": {
"aliases": ["r"],
"help": "Run Code.",
"args": [
{
"name": "file",
"help": "Target file in the format module:content or path.to.module:content",
},
{"name": "--host", "default": "127.0.0.1", "help": "Host to bind to"},
{"name": "--port", "type": int, "default": 8000, "help": "Port to bind to"},
{
"name": "--reload",
"type": bool,
"default": True,
"help": "Use Hot Reload",
},
{
"name": "--time",
"type": float,
"default": 0.5,
"help": "HotReload sleep time.",
},
{
"name": "--static-dir",
"type": str,
"default": ".",
"help": "Static files directory",
},
],
},
"build": {
"aliases": ["b"],
"help": "Build the application",
"args": [
{"name": "file", "help": "Target file in the format module:content"},
{
"name": "--out",
"required": False,
"default": None,
"help": "Output path",
},
],
},
"convert": {
"aliases": ["c"],
"help": "Convert HTML to INUI.",
"args": [
{"name": "--html", "required": False, "help": "HTML content as a string"},
{
"name": "--url",
"required": False,
"help": "URL to fetch HTML content from",
},
{"name": "--file_name", "required": False, "help": "Path to the HTML file"},
{
"name": "--out",
"required": False,
"help": "Path to save the output file",
},
{
"name": "--indent",
"type": int,
"required": False,
"default": 4,
"help": "Indentation level for output",
},
],
},
}


def create_parser():
parser = argparse.ArgumentParser(
prog="inui",
description="CLI for INUI: A Powerful and Highly Customizable Python Library for UI",
)
subparsers = parser.add_subparsers(
dest="command", required=True, help="Available subcommands"
)

alias_map = {}
for cmd, config in COMMANDS.items():
alias_list = ", ".join(config["aliases"])
subparser = subparsers.add_parser(
cmd,
help=f"{config['help']} (aliases: {alias_list})",
description=f"{config['help']} (aliases: {alias_list})",
)
for arg in config["args"]:
subparser.add_argument(arg.pop("name"), **arg)
for alias in config["aliases"]:
alias_map[alias] = cmd

return parser, alias_map


def main():
parser, alias_map = create_parser()

if len(sys.argv) > 1 and sys.argv[1] in alias_map:
sys.argv[1] = alias_map[sys.argv[1]]

args = parser.parse_args()

if args.command == "run":
module_name, variable_name = args.file.split(":")

hot_reload(
host=args.host,
port=args.port,
module=module_name,
variable_name=variable_name,
sleep_time=args.time,
static_dir=args.static_dir,
)
if args.command == "build":
module_name, variable_name = args.file.split(":")
build(
module=module_name,
variable=variable_name,
out=args.out,
)

if args.command == "convert":
convert(
html=args.html,
url=args.url,
file_name=args.file_name,
save_to=args.out,
indent=args.indent,
)


if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion inui/bases/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def _str(self, data, seperator=" ", fill=""):
for key, value in data.items():
result += f"{self._str(key)}: {self._str(value)};"
return f"{fill}{result}{fill}"
return str(data)
return str(data).replace('"', '\\"') #! we have problem with quotation.

def copy(self):
return self.attrs.copy()
Expand Down
77 changes: 39 additions & 38 deletions inui/hotreload.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import argparse
import asyncio
import http.server
import importlib.util
Expand All @@ -17,29 +16,18 @@
except ImportError:
raise "you must install watchdog, run `python3 -m pip install watchdog"

file_to_watch = ""
variable_name = ""

global _host, _port, _file_to_watch, _variable_name, _sleep_time, _static_dir

_host = "localhost"
_port = 8000
_file_to_watch = ""
_variable_name = ""
clients = set()
sleep_time = 1
static_dir = "."

parser = argparse.ArgumentParser(description="Hot reload HTML content.")
parser.add_argument("module", type=str, help="Module name in the format main:variable")
parser.add_argument("--host", type=str, default="localhost", help="Host address")
parser.add_argument("--port", type=int, default=8000, help="Port number")
parser.add_argument("--sleep", type=float, default=1, help="Sleep time")
parser.add_argument(
"--static-dir", type=str, default=static_dir, help="Static files directory"
)
args = parser.parse_args()

module_name, variable_name = args.module.split(":")
file_to_watch = f"{module_name.replace('.', '/')}.py"
sleep_time = args.sleep
static_dir = args.static_dir
logging.basicConfig(
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
)
_sleep_time = 1
_static_dir = "."
# module_name, variable_name = module.split(":")
# file_to_watch = f"{module_name.replace('.', '/')}.py"


def get_file_contents(file_name, variable_name):
Expand Down Expand Up @@ -99,13 +87,13 @@ async def websocket_handler(websocket, path):


async def update_html_content(*args):
html_content = get_file_contents(file_to_watch, variable_name)
html_content = get_file_contents(_file_to_watch, _variable_name)
if not isinstance(html_content, str):
html_content = str(html_content)
await send_update(html_content)


def monitor_file(file_to_watch: str, sleep_time: float):
def monitor_file(_file_to_watch: str, sleep_time: float):
event_handler = HTMLFileHandler()
observer = Observer()
observer.schedule(event_handler, path=os.getcwd(), recursive=False)
Expand All @@ -123,8 +111,8 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
if self.path == "/":
content = get_file_contents(
file_to_watch, variable_name
) + hot_reload_script(host=args.host, port=args.port + 1)
_file_to_watch, _variable_name
) + hot_reload_script(host=_host, port=_port + 1)
self.send_response(200)
self.send_header("Content-type", "text/html")
self.send_header(
Expand All @@ -134,7 +122,7 @@ def do_GET(self):
self.wfile.write(str(content).encode())
logging.info("Served HTML content.")
else:
self.path = f"/{static_dir}{self.path}"
self.path = f"/{_static_dir}{self.path}"
super().do_GET()


Expand All @@ -144,32 +132,45 @@ def run_server(host, port):
httpd.serve_forever()


def main():
def hot_reload(
host: str,
port: int,
module: str,
variable_name: str,
sleep_time: float,
static_dir: str,
):
global _host, _port, _file_to_watch, _variable_name, _sleep_time, _static_dir
file_to_watch = f"{module.replace('.', '/')}.py"

_host, _port, _file_to_watch, _variable_name, _sleep_time, _static_dir = (
host,
port,
file_to_watch,
variable_name,
sleep_time,
static_dir,
)

def run_async():
new_loop = asyncio.new_event_loop()
asyncio.set_event_loop(new_loop)

async def start_websocket_server():
start_server = await websockets.serve(
lambda x: websocket_handler(x, file_to_watch), args.host, args.port + 1
lambda x: websocket_handler(x, _file_to_watch), host, port + 1
)
await start_server.wait_closed()

new_loop.run_until_complete(start_websocket_server())

threading.Thread(
target=monitor_file, args=(file_to_watch, sleep_time), daemon=True
target=monitor_file, args=(_file_to_watch, _sleep_time), daemon=True
).start()

threading.Thread(
target=run_server, args=(args.host, args.port), daemon=True
).start()
threading.Thread(target=run_server, args=(host, port), daemon=True).start()

websocket_thread = threading.Thread(target=run_async, daemon=True)
websocket_thread.start()

websocket_thread.join()


if __name__ == "__main__":
main()
Loading

0 comments on commit 87a07a5

Please sign in to comment.