diff --git a/pdm.lock b/pdm.lock index 711871c..83967ee 100644 --- a/pdm.lock +++ b/pdm.lock @@ -2,10 +2,10 @@ # It is not intended for manual editing. [metadata] -groups = ["default"] +groups = ["default", "dev"] strategy = ["cross_platform", "inherit_metadata"] lock_version = "4.4.1" -content_hash = "sha256:279342c627cd959b3778da7869588891b233fbe6026adda524f3dbb40efc754a" +content_hash = "sha256:e413275e302110dc936b03eeb7bd6ae9ded1f75c05d498707183fc80e1e24013" [[package]] name = "attrs" @@ -18,6 +18,28 @@ files = [ {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, ] +[[package]] +name = "black" +version = "24.4.2" +requires_python = ">=3.8" +summary = "The uncompromising code formatter." +groups = ["dev"] +dependencies = [ + "click>=8.0.0", + "mypy-extensions>=0.4.3", + "packaging>=22.0", + "pathspec>=0.9.0", + "platformdirs>=2", +] +files = [ + {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, + {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, + {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, + {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, + {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, + {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, +] + [[package]] name = "certifi" version = "2024.6.2" @@ -53,6 +75,32 @@ files = [ {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, ] +[[package]] +name = "click" +version = "8.1.7" +requires_python = ">=3.7" +summary = "Composable command line interface toolkit" +groups = ["dev"] +dependencies = [ + "colorama; platform_system == \"Windows\"", +] +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[[package]] +name = "colorama" +version = "0.4.6" +requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +summary = "Cross-platform colored terminal text." +groups = ["dev"] +marker = "platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + [[package]] name = "fire" version = "0.6.0" @@ -103,6 +151,28 @@ files = [ {file = "InquirerPy-0.3.4.tar.gz", hash = "sha256:89d2ada0111f337483cb41ae31073108b2ec1e618a49d7110b0d7ade89fc197e"}, ] +[[package]] +name = "isort" +version = "5.13.2" +requires_python = ">=3.8.0" +summary = "A Python utility / library to sort Python imports." +groups = ["dev"] +files = [ + {file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"}, + {file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +requires_python = ">=3.5" +summary = "Type system extensions for programs checked with the mypy type checker." +groups = ["dev"] +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + [[package]] name = "outcome" version = "1.3.0.post0" @@ -117,6 +187,28 @@ files = [ {file = "outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8"}, ] +[[package]] +name = "packaging" +version = "24.0" +requires_python = ">=3.7" +summary = "Core utilities for Python packages" +groups = ["dev"] +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +requires_python = ">=3.8" +summary = "Utility library for gitignore style pattern matching of file paths." +groups = ["dev"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + [[package]] name = "pfzy" version = "0.3.4" @@ -128,6 +220,17 @@ files = [ {file = "pfzy-0.3.4.tar.gz", hash = "sha256:717ea765dd10b63618e7298b2d98efd819e0b30cd5905c9707223dceeb94b3f1"}, ] +[[package]] +name = "platformdirs" +version = "4.2.2" +requires_python = ">=3.8" +summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +groups = ["dev"] +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + [[package]] name = "prompt-toolkit" version = "3.0.46" @@ -182,6 +285,32 @@ files = [ {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] +[[package]] +name = "ruff" +version = "0.4.8" +requires_python = ">=3.7" +summary = "An extremely fast Python linter and code formatter, written in Rust." +groups = ["dev"] +files = [ + {file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"}, + {file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"}, + {file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"}, + {file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"}, + {file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"}, + {file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"}, + {file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"}, + {file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"}, +] + [[package]] name = "schedule" version = "1.2.2" diff --git a/pyproject.toml b/pyproject.toml index c68978d..4ced77e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,3 +26,19 @@ build-backend = "pdm.backend" [tool.pdm] distribution = true + +[tool.pdm.dev-dependencies] +dev = [ + "black>=24.4.2", + "isort>=5.13.2", + "ruff>=0.4.8", +] + +[tool.black] +line-length = 120 + +[tool.isort] +profile = "black" + +[tool.ruff] +line-length = 120 \ No newline at end of file diff --git a/src/autolms/__init__.py b/src/autolms/__init__.py index 6468184..210e7be 100644 --- a/src/autolms/__init__.py +++ b/src/autolms/__init__.py @@ -1 +1,3 @@ -from autolms.main import run, go +from autolms.main import go, run + +__all__ = ["go", "run"] diff --git a/src/autolms/config.py b/src/autolms/config.py index 33e252d..f3da852 100644 --- a/src/autolms/config.py +++ b/src/autolms/config.py @@ -10,7 +10,7 @@ from InquirerPy.utils import color_print from InquirerPy.validator import PathValidator -yml_path = Path.home() / Path('config.yml') +yml_path = Path.home() / Path("config.yml") def find(name, path, tl=None): @@ -26,7 +26,7 @@ def find(name, path, tl=None): def find_chromedriver(tl): chromedriver = "chromedriver" - if os.name == 'nt': + if os.name == "nt": chromedriver = "chromedriver.exe" paths = [Path.home() / "Downloads", Path.home() / "Desktop", Path("/")] start = time.time() @@ -37,7 +37,7 @@ def find_chromedriver(tl): color_print([("#00E676", "Found!")]) return f color_print([("#B00020", "Not Found!")]) - return '' + return "" def find_id(url_or_id): @@ -70,7 +70,7 @@ def find_id(url_or_id): "name": "password", "message": "Enter your LMS Password:", "validate": lambda x: len(x) > 0, - } + }, ] options_questions = [ @@ -99,7 +99,7 @@ def find_id(url_or_id): "filter": lambda x: find_id(x), "transformer": lambda x: find_id(x), "long_instruction": "URL Something like `lms.com/course/view.php?id=1194` or just ID like `1194`", - } + }, ] session_questions = [ @@ -122,7 +122,7 @@ def find_id(url_or_id): "name": "time", "message": "Enter the Session Time:", "instruction": "(HH:MM Format)", - "validate": lambda x: re.match(r"^([0-2]\d:)?[0-5]\d:[0-5]\d$", x) + "validate": lambda x: re.match(r"^([0-2]\d:)?[0-5]\d:[0-5]\d$", x), }, ] @@ -133,9 +133,9 @@ def find_id(url_or_id): "name": "chromedriver", "validate": PathValidator(is_file=True, message="Input is not a file"), "long_instruction": "If you don't know what is this, checkout:\n" - "https://github.com/itsamirhn/AutoLMS#how-to-download-chromedriver", + "https://github.com/itsamirhn/AutoLMS#how-to-download-chromedriver", "filter": lambda file: str(Path(file).absolute()), - "default": lambda _: find_chromedriver(10) + "default": lambda _: find_chromedriver(10), }, ] @@ -151,8 +151,9 @@ def prompt_course(): finished = False while not finished: course["sessions"].append(prompt_session()) - finished = inquirer.confirm("Are you finished adding Sessions for %s course ?" % course["name"], - default=True).execute() + finished = inquirer.confirm( + "Are you finished adding Sessions for %s course ?" % course["name"], default=True + ).execute() return course @@ -161,7 +162,7 @@ def prompt_config(): "credentials": prompt(credentials_questions), "paths": prompt(paths_questions), "options": prompt(options_questions), - "courses": [] + "courses": [], } finished = False while not finished: @@ -174,7 +175,7 @@ def save_config(config): if not config: return color_print([("#00E676", "New Config saved successfully!")]) - with open(yml_path, 'w+') as f: + with open(yml_path, "w+") as f: yaml.safe_dump(config, f) @@ -189,7 +190,7 @@ def setup(): def get_config(): if Path(yml_path).exists(): - with open(yml_path, 'r') as f: + with open(yml_path, "r") as f: config = yaml.safe_load(f) return config else: @@ -197,12 +198,14 @@ def get_config(): def edit_session(session): - action = inquirer.select(message="What to you want to do with the Session:", - instruction="%s on %s" % (session["time"], session["day"].title()), - choices=[ - Choice("edit", "Edit this Session"), - Choice("delete", "Delete this Session"), - ]).execute() + action = inquirer.select( + message="What to you want to do with the Session:", + instruction="%s on %s" % (session["time"], session["day"].title()), + choices=[ + Choice("edit", "Edit this Session"), + Choice("delete", "Delete this Session"), + ], + ).execute() if action == "delete": return None if action == "edit": @@ -234,11 +237,14 @@ def edit_course(course): def edit_config(config): - sections = inquirer.select(message="Which section do you want to change:", choices=[ - Choice("credentials", name="Credentials"), - Choice("options", name="Options"), - Choice("courses", name="Courses"), - ]).execute() + sections = inquirer.select( + message="Which section do you want to change:", + choices=[ + Choice("credentials", name="Credentials"), + Choice("options", name="Options"), + Choice("courses", name="Courses"), + ], + ).execute() if sections == "credentials": config["credentials"] = prompt(credentials_questions) if sections == "options": diff --git a/src/autolms/core.py b/src/autolms/core.py index 759da6b..b600d15 100644 --- a/src/autolms/core.py +++ b/src/autolms/core.py @@ -80,7 +80,8 @@ def login(self, tries=3): redirect.click() self.driver.find_element(By.XPATH, "//input[@id='username' or @name='name']").send_keys(self.username) self.driver.find_element(By.XPATH, "//input[@id='password' or @name='pass']").send_keys( - self.password + Keys.RETURN) + self.password + Keys.RETURN + ) if self.driver.current_url == self.login_url: if tries > 0: self.login(tries - 1) @@ -94,7 +95,7 @@ def go_to_my(self): def go_to_last_event(self): if self.driver.current_url != self.my_url: self.go_to_my() - self.click(By.CSS_SELECTOR, 'a[data-type=event]') + self.click(By.CSS_SELECTOR, "a[data-type=event]") self.click_text_multiple("رفتن به فعالیت", "Go to activity") if "adobeconnect" in self.driver.current_url: self.go_to_adobeconnect() @@ -107,16 +108,19 @@ def go_to_adobeconnect(self, browser: bool = True): self.click(By.CLASS_NAME, "aconbtnjoin") self.driver.switch_to.window(self.driver.window_handles[1]) wait = WebDriverWait(self.driver, 30) - button = wait.until(expected_conditions.element_to_be_clickable( - (By.CSS_SELECTOR, "div.open-in-{}-button div.button-content".format("browser" if browser else "app")))) + button = wait.until( + expected_conditions.element_to_be_clickable( + (By.CSS_SELECTOR, "div.open-in-{}-button div.button-content".format("browser" if browser else "app")) + ) + ) action = ActionChains(self.driver) action.move_to_element(button).click().perform() if not browser: return self.driver.maximize_window() - iframe = wait.until(expected_conditions.visibility_of_element_located( - (By.CSS_SELECTOR, "iframe[name=html-meeting-view-frame]") - )) + iframe = wait.until( + expected_conditions.visibility_of_element_located((By.CSS_SELECTOR, "iframe[name=html-meeting-view-frame]")) + ) self.driver.switch_to.frame(iframe) self.click(By.CLASS_NAME, "spectrum-Button--secondary", 30) @@ -125,16 +129,19 @@ def go_to_onlineclass(self, browser: bool = True): raise Exception("Driver is not on Onlineclass event!") self.click(By.CSS_SELECTOR, "input[name=submitbutton]") wait = WebDriverWait(self.driver, 30) - button = wait.until(expected_conditions.element_to_be_clickable( - (By.CSS_SELECTOR, "div.open-in-{}-button div.button-content".format("browser" if browser else "app")))) + button = wait.until( + expected_conditions.element_to_be_clickable( + (By.CSS_SELECTOR, "div.open-in-{}-button div.button-content".format("browser" if browser else "app")) + ) + ) action = ActionChains(self.driver) action.move_to_element(button).click().perform() if not browser: return self.driver.maximize_window() - iframe = wait.until(expected_conditions.visibility_of_element_located( - (By.CSS_SELECTOR, 'iframe[name=html-meeting-view-frame]') - )) + iframe = wait.until( + expected_conditions.visibility_of_element_located((By.CSS_SELECTOR, "iframe[name=html-meeting-view-frame]")) + ) self.driver.switch_to.frame(iframe) self.click(By.CLASS_NAME, "spectrum-Button--secondary", 30) @@ -143,8 +150,10 @@ def go_to_course(self, course_id): def go_to_course_last_event(self, course_id): self.go_to_course(course_id) - self.click(By.XPATH, - "//li[(contains(@class,'adobeconnect') or contains(@class,'onlineclass')) and not(contains(., 'رزرو'))][last()]//a") + self.click( + By.XPATH, + "//li[(contains(@class,'adobeconnect') or contains(@class,'onlineclass')) and not(contains(., 'رزرو'))][last()]//a", + ) if "adobeconnect" in self.driver.current_url: self.go_to_adobeconnect() elif "onlineclass" in self.driver.current_url: diff --git a/src/autolms/main.py b/src/autolms/main.py index 777a0a3..4d1be19 100644 --- a/src/autolms/main.py +++ b/src/autolms/main.py @@ -56,11 +56,13 @@ def run(alert=False): return for course in cfg["courses"]: for session in course["sessions"]: - session_time = datetime.datetime.strptime(session["time"], "%H:%M") \ - - datetime.timedelta(seconds=int(cfg["options"]["rush"])) + session_time = datetime.datetime.strptime(session["time"], "%H:%M") - datetime.timedelta( + seconds=int(cfg["options"]["rush"]) + ) rushed_time = session_time.strftime("%H:%M:%S") - getattr(schedule.every(), session["day"]).at(rushed_time).do(go, course_id=course["id"], - course_name=course["name"]) + getattr(schedule.every(), session["day"]).at(rushed_time).do( + go, course_id=course["id"], course_name=course["name"] + ) print("Add job for %s on %s at %s" % (course["name"], session["day"], rushed_time)) print("Running schedule...") while True: @@ -72,12 +74,14 @@ def run(alert=False): def main(): - fire.Fire({ - "go": go, - "run": run, - "setup": setup, - "edit": edit, - }) + fire.Fire( + { + "go": go, + "run": run, + "setup": setup, + "edit": edit, + } + ) if __name__ == "__main__":