Skip to content

Commit

Permalink
modify schema + replace helium with selenium
Browse files Browse the repository at this point in the history
  • Loading branch information
shravanasati committed May 22, 2024
1 parent 4466b96 commit 287e833
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 269 deletions.
244 changes: 41 additions & 203 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ stella = "stellapy.stella:main"
[tool.poetry.dependencies]
python = "^3.10"
click = "^8.1.7"
helium = "^4.0.0"
rich = "^13.7.0"
ruamel-yaml = "^0.18.5"
gitignorefile = "^1.1.2"
jsonschema = "^4.20.0"
watchdog = "^4.0.0"
selenium = "^4.21.0"


[build-system]
Expand Down
9 changes: 2 additions & 7 deletions schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"properties": {
"browser": {
"type": "string",
"enum": ["chrome", "firefox"],
"enum": ["chrome", "firefox", "edge", "safari"],
"description": "The browser to be used."
},
"include_only": {
Expand All @@ -32,19 +32,14 @@
"browser_wait_interval": {
"type": "number",
"description": "The interval in milliseconds to wait to refresh browser window after executing command(s) on the terminal."
},
"follow_symlinks": {
"type": "boolean",
"description": "Whether to follow symbolic links encountered in the directory tree."
}
},
"required": [
"browser",
"include_only",
"poll_interval",
"browser_wait_interval",
"scripts",
"follow_symlinks"
"scripts"
],
"title": "Stella"
},
Expand Down
1 change: 0 additions & 1 deletion stella.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/shravanasati/stellapy/master/schema.json

browser: "firefox"
follow_symlinks: false
include_only: ["*.py"]
poll_interval: 500
browser_wait_interval: 1000
Expand Down
5 changes: 2 additions & 3 deletions stellapy/configuration.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import logging
import os
from dataclasses import asdict, dataclass
from io import StringIO
Expand Down Expand Up @@ -56,7 +57,6 @@ class Configuration:
include_only: list[str]
poll_interval: float # milliseconds
browser_wait_interval: float
follow_symlinks: bool
scripts: list[Script]

@classmethod
Expand All @@ -67,7 +67,6 @@ def default(cls):
scripts=[Script("default", "", "echo 'hello'", True)],
poll_interval=500,
browser_wait_interval=1000,
follow_symlinks=False,
)

def to_yaml(self):
Expand Down Expand Up @@ -178,7 +177,7 @@ def load_configuration_handle_errors(
except ValidationError as ve:
log(
"error",
f"{IMPROPER_CONFIG_HELP_TEXT}\n\tvalidation error: {ve}",
f"{IMPROPER_CONFIG_HELP_TEXT}\nvalidation error: {ve}",
)
exit(1)
except Exception as e:
Expand Down
92 changes: 43 additions & 49 deletions stellapy/reloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from time import sleep
from typing import Any, Callable, Generic, TypeVar

import helium
from selenium import webdriver
from watchdog.observers import Observer

from stellapy.configuration import Configuration
Expand Down Expand Up @@ -105,7 +105,9 @@ def __init__(
# watchdog observer
self.observer = Observer()
self.observer.schedule(
PatternMatchingEventHandler(self.config.include_only, self._restart),
PatternMatchingEventHandler(
self.config.include_only, self.config.poll_interval, self._restart
),
".",
recursive=True,
)
Expand Down Expand Up @@ -133,56 +135,47 @@ def _trigger_executor(self):
sleep(self.trigger_execution_interval)

def start_browser(self):
browser = self.config.browser
if browser == "chrome":
try:
helium.start_chrome(self.url)
except Exception as e:
if "Message: unknown error: cannot find Chrome binary" in str(e):
log(
"error",
"chrome binary not found. either install chrome browser or configure stella browser to firefox.",
)
self.stop()

elif "Reached error page" in str(e):
log("error", "app crashed, waiting for file changes to restart...")

else:
log("error", f"an unknown error occurred: \n{e}")
self.stop()

elif browser == "firefox":
try:
helium.start_firefox(self.url)
except Exception as e:
if "Message: unknown error: cannot find Firefox binary" in str(e):
log(
"error",
"firefox binary not found. either install chrome browser or configure stella to use firefox.",
)
self.stop()
# selenium driver
if self.config.browser not in ("firefox", "chrome", "safari", "edge"):
# this should never happen because of configuration validation
raise Exception(f"invalid browser={self.config.browser}")

match self.config.browser.lower():
case "firefox":
self.driver = webdriver.Firefox()
case "chrome":
self.driver = webdriver.Chrome()
case "safari":
self.driver = webdriver.Safari()
case "edge":
self.driver = webdriver.Edge()
case _:
raise Exception(f"unknown browser={self.config.browser}")

elif "Message: Reached error page" in str(e):
log("error", "app crashed, waiting for file changes to restart...")
try:
# todo handle selenium manager exception
# todo edit schema.json
self.driver.get(self.url)
except Exception as e:
if "Message: unknown error: cannot find Chrome binary" in str(e):
log(
"error",
"chrome binary not found. either install chrome browser or configure stella browser to firefox.",
)
self.stop()

else:
log("error", f"an unknown error occurred: \n{e}")
self.stop()
elif "Reached error page" in str(e):
log("error", "app crashed, waiting for file changes to restart...")

else:
log(
"error",
f"invalid browser specified: {browser}. stella supports only chrome and firefox. execute `stella config --browser chrome|firefox` for configuring the browser.",
)
self.stop()
else:
log("error", f"an unknown error occurred: \n{e}")
self.stop()

@staticmethod
def _browser_reloader(_: Trigger[timedelta]):
def _browser_reloader(self, _: Trigger[timedelta]):
"""
A helper function used in browser reload triggers.
"""
helium.refresh()
self.driver.refresh()

@staticmethod
def _displayable_seconds_from_timedelta(t: timedelta):
Expand Down Expand Up @@ -265,7 +258,7 @@ def manual_input(self) -> None:
if self.RELOAD_BROWSER:
try:
log("info", "trying to reload browser window")
helium.refresh()
self.driver.refresh()
except Exception:
log("error", "unable to refresh browser window")
else:
Expand Down Expand Up @@ -296,7 +289,7 @@ def stop(self):
try:
self.executor.close()
if self.RELOAD_BROWSER:
helium.kill_browser()
self.driver.quit()
except Exception as e:
log(
"error",
Expand All @@ -305,8 +298,9 @@ def stop(self):
exception(e)
finally:
self._finished = True
self.observer.stop()
self.observer.join()
if self.observer.is_alive():
self.observer.stop()
self.observer.join()

def start(self) -> None:
"""
Expand Down
26 changes: 21 additions & 5 deletions stellapy/walker.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@
from typing import Callable, Iterable

import gitignorefile
from watchdog.events import FileSystemEvent, FileSystemEventHandler, EVENT_TYPE_CLOSED, EVENT_TYPE_OPENED
from watchdog.events import (
EVENT_TYPE_CLOSED,
EVENT_TYPE_OPENED,
FileSystemEvent,
FileSystemEventHandler,
)


def get_ignore_include_patterns(include_only: Iterable[str] | None):
Expand All @@ -28,15 +33,26 @@ class PatternMatchingEventHandler(FileSystemEventHandler):
Subclass of `watchdog.FileSystemEventHandler` which implements gitignore-style
pattern matching.
"""
def __init__(self, include_only: Iterable[str] | None, callback: Callable[[], None]) -> None:

def __init__(
self,
include_only: Iterable[str] | None,
poll_interval: float,
callback: Callable[[], None],
) -> None:
super().__init__()
self.ignore_match, self.include_match = get_ignore_include_patterns(include_only)
self.ignore_match, self.include_match = get_ignore_include_patterns(
include_only
)
self.poll_interval = poll_interval
self.callback_fn = callback
self.last_event_time = datetime.now()

def on_any_event(self, event: FileSystemEvent) -> None:
# only respond to events after a certain threshold
if datetime.now() - self.last_event_time > timedelta(milliseconds=500):
if datetime.now() - self.last_event_time > timedelta(
milliseconds=self.poll_interval
):
super().on_any_event(event)
self.callback_fn()
self.last_event_time = datetime.now()
Expand All @@ -46,7 +62,7 @@ def dispatch(self, event: FileSystemEvent) -> None:
self.ignore_match(event.src_path),
".git" in event.src_path,
event.event_type in (EVENT_TYPE_OPENED, EVENT_TYPE_CLOSED),
not self.include_match(event.src_path)
not self.include_match(event.src_path),
}
if any(no_dispatch_conditions):
return
Expand Down

0 comments on commit 287e833

Please sign in to comment.