From ced0fe684c3b0f59e1639e350f3450a78b0a876c Mon Sep 17 00:00:00 2001 From: killian <63927363+KillianLucas@users.noreply.github.com> Date: Sat, 9 Dec 2023 23:27:08 -0800 Subject: [PATCH] The New Computer Update --- interpreter/core/computer/computer.py | 77 +- .../{languages => display}/__init__.py | 0 interpreter/core/computer/display/display.py | 53 + .../core/computer/keyboard/__init__.py | 0 .../core/computer/keyboard/keyboard.py | 38 + interpreter/core/computer/mouse/__init__.py | 0 interpreter/core/computer/mouse/mouse.py | 79 ++ .../core/computer/terminal/__init__.py | 0 .../computer/{ => terminal}/base_language.py | 0 .../languages/ARCHIVE_subprocess_python.py | 2 +- .../computer/terminal/languages/__init__.py | 0 .../{ => terminal}/languages/applescript.py | 2 +- .../computer/{ => terminal}/languages/html.py | 0 .../{ => terminal}/languages/javascript.py | 2 +- .../languages}/jupyter_language.py | 26 +- .../{ => terminal}/languages/powershell.py | 2 +- .../{ => terminal}/languages/python.py | 2 +- .../computer/{ => terminal}/languages/r.py | 2 +- .../{ => terminal}/languages/react.py | 0 .../{ => terminal}/languages/shell.py | 2 +- .../languages}/subprocess_language.py | 2 +- .../core/computer/terminal/terminal.py | 47 + .../core/computer/utils/computer_vision.py | 293 +++++ .../utils/html_to_png_base64.py | 2 +- interpreter/core/core.py | 7 +- interpreter/core/generate_system_message.py | 1 + .../rag/get_relevant_procedures_string.py | 17 +- .../core/utils/convert_to_openai_messages.py | 2 +- interpreter/core/utils/scan_code.py | 15 +- .../components/code_block.py | 12 +- .../components/message_block.py | 23 - .../render_past_conversation.py | 5 + .../start_terminal_interface.py | 75 +- .../terminal_interface/terminal_interface.py | 62 +- poetry.lock | 1046 ++++++++++++++++- pyproject.toml | 17 +- tests/test_interpreter.py | 6 + 37 files changed, 1759 insertions(+), 160 deletions(-) rename interpreter/core/computer/{languages => display}/__init__.py (100%) create mode 100644 interpreter/core/computer/display/display.py create mode 100644 interpreter/core/computer/keyboard/__init__.py create mode 100644 interpreter/core/computer/keyboard/keyboard.py create mode 100644 interpreter/core/computer/mouse/__init__.py create mode 100644 interpreter/core/computer/mouse/mouse.py create mode 100644 interpreter/core/computer/terminal/__init__.py rename interpreter/core/computer/{ => terminal}/base_language.py (100%) rename interpreter/core/computer/{ => terminal}/languages/ARCHIVE_subprocess_python.py (98%) create mode 100644 interpreter/core/computer/terminal/languages/__init__.py rename interpreter/core/computer/{ => terminal}/languages/applescript.py (97%) rename interpreter/core/computer/{ => terminal}/languages/html.py (100%) rename interpreter/core/computer/{ => terminal}/languages/javascript.py (96%) rename interpreter/core/computer/{ => terminal/languages}/jupyter_language.py (91%) rename interpreter/core/computer/{ => terminal}/languages/powershell.py (97%) rename interpreter/core/computer/{ => terminal}/languages/python.py (84%) rename interpreter/core/computer/{ => terminal}/languages/r.py (97%) rename interpreter/core/computer/{ => terminal}/languages/react.py (100%) rename interpreter/core/computer/{ => terminal}/languages/shell.py (98%) rename interpreter/core/computer/{ => terminal/languages}/subprocess_language.py (99%) create mode 100644 interpreter/core/computer/terminal/terminal.py create mode 100644 interpreter/core/computer/utils/computer_vision.py rename interpreter/core/{ => computer}/utils/html_to_png_base64.py (91%) diff --git a/interpreter/core/computer/computer.py b/interpreter/core/computer/computer.py index 07a954f629..b9498c7b98 100644 --- a/interpreter/core/computer/computer.py +++ b/interpreter/core/computer/computer.py @@ -1,50 +1,47 @@ -from .languages.applescript import AppleScript -from .languages.html import HTML -from .languages.javascript import JavaScript -from .languages.powershell import PowerShell -from .languages.python import Python -from .languages.r import R -from .languages.shell import Shell +from .terminal.terminal import Terminal -language_map = { - "python": Python, - "bash": Shell, - "shell": Shell, - "sh": Shell, - "zsh": Shell, - "javascript": JavaScript, - "html": HTML, - "applescript": AppleScript, - "r": R, - "powershell": PowerShell, -} +try: + from .display.display import Display + from .keyboard.keyboard import Keyboard + from .mouse.mouse import Mouse +except ImportError or ModuleNotFoundError: + raise + pass class Computer: def __init__(self): - self.languages = [Python, Shell, JavaScript, HTML, AppleScript, R, PowerShell] - self._active_languages = {} - - def run(self, language, code): - if language not in self._active_languages: - self._active_languages[language] = language_map[language]() + self.terminal = Terminal() try: - yield from self._active_languages[language].run(code) - except GeneratorExit: - self.stop() + self.mouse = Mouse( + self + ) # Mouse will use the computer's display, so we give it a reference to ourselves + self.keyboard = Keyboard() + self.display = Display() + except: + raise + pass + + def run(self, *args, **kwargs): + """ + Shortcut for computer.terminal.run + """ + return self.terminal.run(*args, **kwargs) def stop(self): - for language in self._active_languages.values(): - language.stop() + """ + Shortcut for computer.terminal.stop + """ + return self.terminal.stop() def terminate(self): - for language_name in list(self._active_languages.keys()): - language = self._active_languages[language_name] - if ( - language - ): # Not sure why this is None sometimes. We should look into this - language.terminate() - del self._active_languages[language_name] - - -computer = Computer() + """ + Shortcut for computer.terminal.terminate + """ + return self.terminal.terminate() + + def screenshot(self, *args, **kwargs): + """ + Shortcut for computer.display.screenshot + """ + return self.display.screenshot(*args, **kwargs) diff --git a/interpreter/core/computer/languages/__init__.py b/interpreter/core/computer/display/__init__.py similarity index 100% rename from interpreter/core/computer/languages/__init__.py rename to interpreter/core/computer/display/__init__.py diff --git a/interpreter/core/computer/display/display.py b/interpreter/core/computer/display/display.py new file mode 100644 index 0000000000..84b00479f2 --- /dev/null +++ b/interpreter/core/computer/display/display.py @@ -0,0 +1,53 @@ +import os +import tempfile + +import matplotlib.pyplot as plt +import numpy as np +import pyautogui +from PIL import Image + + +class Display: + def screenshot(self, show=True, quadrant=None): + temp_file = tempfile.NamedTemporaryFile(suffix=".png", delete=False) + + if quadrant == None: + screenshot = pyautogui.screenshot() + else: + try: + screen_width, screen_height = pyautogui.size() + except: + raise EnvironmentError("Unable to determine screen size.") + + quadrant_width = screen_width // 2 + quadrant_height = screen_height // 2 + + quadrant_coordinates = { + 1: (0, 0), + 2: (quadrant_width, 0), + 3: (0, quadrant_height), + 4: (quadrant_width, quadrant_height), + } + + if quadrant in quadrant_coordinates: + x, y = quadrant_coordinates[quadrant] + screenshot = pyautogui.screenshot( + region=(x, y, quadrant_width, quadrant_height) + ) + else: + raise ValueError("Invalid quadrant. Choose between 1 and 4.") + + screenshot.save(temp_file.name) + + # Open the image file with PIL + img = Image.open(temp_file.name) + + # Delete the temporary file + os.remove(temp_file.name) + + if show: + # Show the image using matplotlib + plt.imshow(np.array(img)) + plt.show() + + return img diff --git a/interpreter/core/computer/keyboard/__init__.py b/interpreter/core/computer/keyboard/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/interpreter/core/computer/keyboard/keyboard.py b/interpreter/core/computer/keyboard/keyboard.py new file mode 100644 index 0000000000..e8f6594dd5 --- /dev/null +++ b/interpreter/core/computer/keyboard/keyboard.py @@ -0,0 +1,38 @@ +import platform +import random +import time + +import pyautogui + +pyautogui.FAILSAFE = False + + +class Keyboard: + def write(self, text): + # Split the text into words + words = text.split(" ") + + # Type each word + for word in words: + # Type the word + pyautogui.write(word) + # Add a delay after each word + time.sleep(random.uniform(0.1, 0.3)) + + def press(self, keys): + pyautogui.press(keys) + + def hotkey(self, *args): + if "darwin" in platform.system().lower(): + # For some reason, application focus or something, we need to do this for spotlight + # only if they passed in "command", "space" or "command", " ", or those in another order + if set(args) == {"command", " "} or set(args) == {"command", "space"}: + pyautogui.click(0, 0) + time.sleep(0.5) + pyautogui.hotkey(*args) + + def down(self, key): + pyautogui.keyDown(key) + + def up(self, key): + pyautogui.keyUp(key) diff --git a/interpreter/core/computer/mouse/__init__.py b/interpreter/core/computer/mouse/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/interpreter/core/computer/mouse/mouse.py b/interpreter/core/computer/mouse/mouse.py new file mode 100644 index 0000000000..2e718fa4ef --- /dev/null +++ b/interpreter/core/computer/mouse/mouse.py @@ -0,0 +1,79 @@ +import time + +import matplotlib.pyplot as plt +import numpy as np +import pyautogui +from PIL import Image + +from ..utils.computer_vision import find_text_in_image + +pyautogui.FAILSAFE = False + + +class Mouse: + def __init__(self, computer): + self.computer = computer + + def move(self, *args, x=None, y=None, index=None, svg=None): + if len(args) > 1: + raise ValueError( + "Too many positional arguments provided: click(*args, x=None, y=None, show=True, index=None)" + ) + elif len(args) == 1: + text = args[0] + # Take a screenshot + img = self.computer.screenshot(show=False) + + # Find the text in the screenshot + centers, bounding_box_image = find_text_in_image(img, text) + + # If the text was found + if centers: + # This could be refactored to be more readable + if len(centers) > 1: + if index == None: + print( + f"This text ('{text}') was found multiple times on screen. Please try 'click()' again, but pass in an `index` int to identify which one you want to click. The indices have been drawn on the attached image." + ) + # Show the image using matplotlib + plt.imshow(np.array(bounding_box_image)) + plt.show() + return + else: + center = centers[index] + else: + center = centers[0] + + # Slowly move the mouse from its current position + pyautogui.moveTo(center[0], center[1], duration=0.5) + + else: + plt.imshow(np.array(bounding_box_image)) + plt.show() + print("Your text was not found on the screen. Please try again.") + elif x is not None and y is not None: + # Move to the specified coordinates and click + pyautogui.moveTo(x, y, duration=0.5) + elif svg is not None: + raise NotImplementedError("SVG handling not implemented yet.") + # img = self.computer.screenshot(show=False) + # # Move to the specified coordinates and click + # coordinates = find_svg_in_image(svg, img) + # if coordinates == None: + # print("Not found.") + # return + # pyautogui.moveTo(coordinates[0], coordinates[1], duration=0.5) + # pyautogui.click(coordinates[0], coordinates[1]) + else: + raise ValueError("Either text or both x and y must be provided") + + def click(self, *args, **kwargs): + if args or kwargs: + self.move(*args, **kwargs) + pyautogui.click() + + def down(self): + pyautogui.mouseDown() + + def up(self): + pyautogui.mouseUp() diff --git a/interpreter/core/computer/terminal/__init__.py b/interpreter/core/computer/terminal/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/interpreter/core/computer/base_language.py b/interpreter/core/computer/terminal/base_language.py similarity index 100% rename from interpreter/core/computer/base_language.py rename to interpreter/core/computer/terminal/base_language.py diff --git a/interpreter/core/computer/languages/ARCHIVE_subprocess_python.py b/interpreter/core/computer/terminal/languages/ARCHIVE_subprocess_python.py similarity index 98% rename from interpreter/core/computer/languages/ARCHIVE_subprocess_python.py rename to interpreter/core/computer/terminal/languages/ARCHIVE_subprocess_python.py index be811a177c..1e1eea061f 100644 --- a/interpreter/core/computer/languages/ARCHIVE_subprocess_python.py +++ b/interpreter/core/computer/terminal/languages/ARCHIVE_subprocess_python.py @@ -6,7 +6,7 @@ import shlex import sys -from ..subprocess_language import SubprocessLanguage +from .subprocess_language import SubprocessLanguage class Python(SubprocessLanguage): diff --git a/interpreter/core/computer/terminal/languages/__init__.py b/interpreter/core/computer/terminal/languages/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/interpreter/core/computer/languages/applescript.py b/interpreter/core/computer/terminal/languages/applescript.py similarity index 97% rename from interpreter/core/computer/languages/applescript.py rename to interpreter/core/computer/terminal/languages/applescript.py index bc28efa3a5..365bc9002b 100644 --- a/interpreter/core/computer/languages/applescript.py +++ b/interpreter/core/computer/terminal/languages/applescript.py @@ -1,6 +1,6 @@ import os -from ..subprocess_language import SubprocessLanguage +from .subprocess_language import SubprocessLanguage class AppleScript(SubprocessLanguage): diff --git a/interpreter/core/computer/languages/html.py b/interpreter/core/computer/terminal/languages/html.py similarity index 100% rename from interpreter/core/computer/languages/html.py rename to interpreter/core/computer/terminal/languages/html.py diff --git a/interpreter/core/computer/languages/javascript.py b/interpreter/core/computer/terminal/languages/javascript.py similarity index 96% rename from interpreter/core/computer/languages/javascript.py rename to interpreter/core/computer/terminal/languages/javascript.py index 301ab37b01..7846ae6a47 100644 --- a/interpreter/core/computer/languages/javascript.py +++ b/interpreter/core/computer/terminal/languages/javascript.py @@ -1,6 +1,6 @@ import re -from ..subprocess_language import SubprocessLanguage +from .subprocess_language import SubprocessLanguage class JavaScript(SubprocessLanguage): diff --git a/interpreter/core/computer/jupyter_language.py b/interpreter/core/computer/terminal/languages/jupyter_language.py similarity index 91% rename from interpreter/core/computer/jupyter_language.py rename to interpreter/core/computer/terminal/languages/jupyter_language.py index f4d08f4e55..c4639f21da 100644 --- a/interpreter/core/computer/jupyter_language.py +++ b/interpreter/core/computer/terminal/languages/jupyter_language.py @@ -3,11 +3,12 @@ import re import threading import time +import traceback import matplotlib from jupyter_client import KernelManager -from .base_language import BaseLanguage +from ..base_language import BaseLanguage DEBUG_MODE = False @@ -47,10 +48,16 @@ def terminate(self): def run(self, code): self.finish_flag = False - preprocessed_code = self.preprocess_code(code) - message_queue = queue.Queue() - self._execute_code(preprocessed_code, message_queue) - yield from self._capture_output(message_queue) + try: + preprocessed_code = self.preprocess_code(code) + message_queue = queue.Queue() + self._execute_code(preprocessed_code, message_queue) + yield from self._capture_output(message_queue) + except GeneratorExit: + raise # gotta pass this up! + except: + content = traceback.format_exc() + yield {"type": "console", "format": "output", "content": content} def _execute_code(self, code, message_queue): def iopub_message_listener(): @@ -197,6 +204,8 @@ def preprocess_python(code): Wrap in a try except """ + code = code.strip() + # Add print commands that tell us what the active line is code = add_active_line_prints(code) @@ -216,6 +225,13 @@ def add_active_line_prints(code): """ Add print statements indicating line numbers to a python string. """ + # Replace newlines and comments with pass statements, so the line numbers are accurate (ast will remove them otherwise) + code_lines = code.split("\n") + for i in range(len(code_lines)): + if code_lines[i].strip().startswith("#") or code_lines[i] == "": + whitespace = len(code_lines[i]) - len(code_lines[i].lstrip()) + code_lines[i] = " " * whitespace + "pass" + code = "\n".join(code_lines) tree = ast.parse(code) transformer = AddLinePrints() new_tree = transformer.visit(tree) diff --git a/interpreter/core/computer/languages/powershell.py b/interpreter/core/computer/terminal/languages/powershell.py similarity index 97% rename from interpreter/core/computer/languages/powershell.py rename to interpreter/core/computer/terminal/languages/powershell.py index acca04c71b..2220571f4e 100644 --- a/interpreter/core/computer/languages/powershell.py +++ b/interpreter/core/computer/terminal/languages/powershell.py @@ -2,7 +2,7 @@ import platform import shutil -from ..subprocess_language import SubprocessLanguage +from .subprocess_language import SubprocessLanguage class PowerShell(SubprocessLanguage): diff --git a/interpreter/core/computer/languages/python.py b/interpreter/core/computer/terminal/languages/python.py similarity index 84% rename from interpreter/core/computer/languages/python.py rename to interpreter/core/computer/terminal/languages/python.py index f69719bcad..1a5870af2c 100644 --- a/interpreter/core/computer/languages/python.py +++ b/interpreter/core/computer/terminal/languages/python.py @@ -1,6 +1,6 @@ import os -from ..jupyter_language import JupyterLanguage +from .jupyter_language import JupyterLanguage # Supresses a weird debugging error os.environ["PYDEVD_DISABLE_FILE_VALIDATION"] = "1" diff --git a/interpreter/core/computer/languages/r.py b/interpreter/core/computer/terminal/languages/r.py similarity index 97% rename from interpreter/core/computer/languages/r.py rename to interpreter/core/computer/terminal/languages/r.py index 67adc47b14..6c33349528 100644 --- a/interpreter/core/computer/languages/r.py +++ b/interpreter/core/computer/terminal/languages/r.py @@ -1,6 +1,6 @@ import re -from ..subprocess_language import SubprocessLanguage +from .subprocess_language import SubprocessLanguage class R(SubprocessLanguage): diff --git a/interpreter/core/computer/languages/react.py b/interpreter/core/computer/terminal/languages/react.py similarity index 100% rename from interpreter/core/computer/languages/react.py rename to interpreter/core/computer/terminal/languages/react.py diff --git a/interpreter/core/computer/languages/shell.py b/interpreter/core/computer/terminal/languages/shell.py similarity index 98% rename from interpreter/core/computer/languages/shell.py rename to interpreter/core/computer/terminal/languages/shell.py index a9b224b4c1..6450bd178d 100644 --- a/interpreter/core/computer/languages/shell.py +++ b/interpreter/core/computer/terminal/languages/shell.py @@ -2,7 +2,7 @@ import platform import re -from ..subprocess_language import SubprocessLanguage +from .subprocess_language import SubprocessLanguage class Shell(SubprocessLanguage): diff --git a/interpreter/core/computer/subprocess_language.py b/interpreter/core/computer/terminal/languages/subprocess_language.py similarity index 99% rename from interpreter/core/computer/subprocess_language.py rename to interpreter/core/computer/terminal/languages/subprocess_language.py index 080d23e9af..0443c21276 100644 --- a/interpreter/core/computer/subprocess_language.py +++ b/interpreter/core/computer/terminal/languages/subprocess_language.py @@ -6,7 +6,7 @@ import time import traceback -from .base_language import BaseLanguage +from ..base_language import BaseLanguage class SubprocessLanguage(BaseLanguage): diff --git a/interpreter/core/computer/terminal/terminal.py b/interpreter/core/computer/terminal/terminal.py new file mode 100644 index 0000000000..e363729557 --- /dev/null +++ b/interpreter/core/computer/terminal/terminal.py @@ -0,0 +1,47 @@ +from .languages.applescript import AppleScript +from .languages.html import HTML +from .languages.javascript import JavaScript +from .languages.powershell import PowerShell +from .languages.python import Python +from .languages.r import R +from .languages.shell import Shell + +language_map = { + "python": Python, + "bash": Shell, + "shell": Shell, + "sh": Shell, + "zsh": Shell, + "javascript": JavaScript, + "html": HTML, + "applescript": AppleScript, + "r": R, + "powershell": PowerShell, +} + + +class Terminal: + def __init__(self): + self.languages = [Python, Shell, JavaScript, HTML, AppleScript, R, PowerShell] + self._active_languages = {} + + def run(self, language, code): + if language not in self._active_languages: + self._active_languages[language] = language_map[language]() + try: + yield from self._active_languages[language].run(code) + except GeneratorExit: + self.stop() + + def stop(self): + for language in self._active_languages.values(): + language.stop() + + def terminate(self): + for language_name in list(self._active_languages.keys()): + language = self._active_languages[language_name] + if ( + language + ): # Not sure why this is None sometimes. We should look into this + language.terminate() + del self._active_languages[language_name] diff --git a/interpreter/core/computer/utils/computer_vision.py b/interpreter/core/computer/utils/computer_vision.py new file mode 100644 index 0000000000..c8c0036ce4 --- /dev/null +++ b/interpreter/core/computer/utils/computer_vision.py @@ -0,0 +1,293 @@ +import io + +import cv2 +import numpy as np +from PIL import Image + + +def find_svg_in_image(svg_code, pil_image): + """ + Not implemented + """ + png_image = cairosvg.svg2png(bytestring=svg_code) + svg_image = Image.open(io.BytesIO(png_image)) + opencv_image = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2GRAY) + + svg_image_array = np.array(svg_image) + if np.any(svg_image_array[:, :, 3] < 255): + non_transparent_pixels = svg_image_array[svg_image_array[:, :, 3] > 0] + avg_color = np.mean(non_transparent_pixels, axis=0) + + dist_black = 1 - np.linalg.norm(avg_color[:3] - [0, 0, 0]) + dist_white = 1 - np.linalg.norm(avg_color[:3] - [255, 255, 255]) + + background_color = (0, 0, 0) if dist_white > dist_black else (255, 255, 255) + background = Image.new("RGB", svg_image.size, background_color) + background.paste(svg_image, mask=svg_image.split()[3]) + opencv_template = cv2.cvtColor(np.array(background), cv2.COLOR_RGB2GRAY) + else: + opencv_template = cv2.cvtColor(np.array(svg_image), cv2.COLOR_RGB2GRAY) + + template_image = opencv_template + source_image = opencv_image + + # Open the images + # cv2.imshow('Image', opencv_image) + # cv2.imshow('Template', opencv_template) + # cv2.waitKey(0) + # cv2.destroyAllWindows() + + # Initialize SIFT detector + sift = cv2.SIFT_create() + + # Find the keypoints and descriptors with SIFT + keypoints_1, descriptors_1 = sift.detectAndCompute(template_image, None) + keypoints_2, descriptors_2 = sift.detectAndCompute(source_image, None) + + # Check if features are detected + if descriptors_1 is None or descriptors_2 is None: + raise ValueError( + "Could not find enough features in one of the images. Try adjusting the SIFT parameters or using a different image." + ) + + # FLANN parameters and matcher + FLANN_INDEX_KDTREE = 1 + index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) + search_params = dict(checks=50) + flann = cv2.FlannBasedMatcher(index_params, search_params) + + matches = flann.knnMatch(descriptors_1, descriptors_2, k=2) + + # Keep good matches: Lowe's ratio test + good_matches = [] + for m, n in matches: + if m and n and m.distance < 1 * n.distance: + good_matches.append(m) + + # Draw all matches (for diagnostic purposes) + img_matches = cv2.drawMatches( + template_image, + keypoints_1, + source_image, + keypoints_2, + good_matches, + None, + flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS, + ) + + # Show all matches + cv2.imshow("All Matches", img_matches) + + # Proceed only if there are enough good matches + if len(good_matches) > 10: + src_pts = np.float32( + [keypoints_1[m.queryIdx].pt for m in good_matches] + ).reshape(-1, 1, 2) + dst_pts = np.float32( + [keypoints_2[m.trainIdx].pt for m in good_matches] + ).reshape(-1, 1, 2) + + # Compute Homography + M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) + matchesMask = mask.ravel().tolist() + + # Get the dimensions of the template image + h, w = template_image.shape[:2] + pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape( + -1, 1, 2 + ) + + # Apply the homography to the template image's corners + dst = cv2.perspectiveTransform(pts, M) + + # Draw bounding box in source image + source_image = cv2.polylines( + source_image, [np.int32(dst)], True, (0, 255, 0), 3, cv2.LINE_AA + ) + cv2.imshow("Detected", source_image) + else: + print(f"Not enough good matches are found - {len(good_matches)}/10") + matchesMask = None + + # Draw matches for visualization + draw_params = dict( + matchColor=(0, 255, 0), singlePointColor=None, matchesMask=matchesMask, flags=2 + ) + + img_matches = cv2.drawMatches( + template_image, + keypoints_1, + source_image, + keypoints_2, + good_matches, + None, + **draw_params, + ) + + # Show the matches + cv2.imshow("Matches", img_matches) + + cv2.waitKey(0) + cv2.destroyAllWindows() + + # Open all images used, using the systems image viewer (not plt) + # print(pil_image.filename) + # print(svg_image.filename) + # os.system('open ' + pil_image.filename) + # os.system('open ' + svg_image.filename) + # try: + # os.startfile(pil_image.filename) + # os.startfile(svg_image.filename) + # except AttributeError: + # import subprocess + # subprocess.call(['open', pil_image.filename]) + # subprocess.call(['open', svg_image.filename]) + + +from pytesseract import Output, pytesseract + + +def find_text_in_image(img, text): + # Convert PIL Image to NumPy array + img_array = np.array(img) + + # Convert the image to grayscale + gray = cv2.cvtColor(img_array, cv2.COLOR_BGR2GRAY) + + # Use pytesseract to get the data from the image + d = pytesseract.image_to_data(gray, output_type=Output.DICT) + + # Initialize an empty list to store the centers of the bounding boxes + centers = [] + + # Get the number of detected boxes + n_boxes = len(d["level"]) + + # Create a copy of the grayscale image to draw on + img_draw = np.array(gray.copy()) + + # Convert the img_draw grayscale image to RGB + img_draw = cv2.cvtColor(img_draw, cv2.COLOR_GRAY2RGB) + + id = 0 + + # Loop through each box + for i in range(n_boxes): + # Print the text of the box + # If the text in the box matches the given text + if text.lower() in d["text"][i].lower(): + # Find the start index of the matching text in the box + start_index = d["text"][i].lower().find(text.lower()) + # Calculate the percentage of the box width that the start of the matching text represents + start_percentage = start_index / len(d["text"][i]) + # Move the left edge of the box to the right by this percentage of the box width + d["left"][i] = d["left"][i] + int(d["width"][i] * start_percentage) + + # Calculate the width of the matching text relative to the entire text in the box + text_width_percentage = len(text) / len(d["text"][i]) + # Adjust the width of the box to match the width of the matching text + d["width"][i] = int(d["width"][i] * text_width_percentage) + + # Calculate the center of the bounding box + center = ( + d["left"][i] + d["width"][i] / 2, + d["top"][i] + d["height"][i] / 2, + ) + + """bounding + + bounding + + bounding + + bounding + + bounding bounding bounding""" + + # Half both coordinates + center = (center[0] / 2, center[1] / 2) + + # Add the center to the list + centers.append(center) + + # Draw the bounding box on the image in red and make it slightly larger + larger = 10 + cv2.rectangle( + img_draw, + (d["left"][i] - larger, d["top"][i] - larger), + ( + d["left"][i] + d["width"][i] + larger, + d["top"][i] + d["height"][i] + larger, + ), + (255, 0, 0), + 7, + ) + + # Create a small black square background for the ID + cv2.rectangle( + img_draw, + ( + d["left"][i] + d["width"][i] // 2 - larger * 2, + d["top"][i] + d["height"][i] // 2 - larger * 2, + ), + ( + d["left"][i] + d["width"][i] // 2 + larger * 2, + d["top"][i] + d["height"][i] // 2 + larger * 2, + ), + (0, 0, 0), + -1, + ) + + # Put the ID in the center of the bounding box in red + cv2.putText( + img_draw, + str(id), + ( + d["left"][i] + d["width"][i] // 2 - larger, + d["top"][i] + d["height"][i] // 2 + larger, + ), + cv2.FONT_HERSHEY_DUPLEX, + 1, + (255, 155, 155), + 4, + ) + + # Increment id + id += 1 + + if not centers: + word_centers = [] + for word in text.split(): + for i in range(n_boxes): + if word.lower() in d["text"][i].lower(): + center = ( + d["left"][i] + d["width"][i] / 2, + d["top"][i] + d["height"][i] / 2, + ) + center = (center[0] / 2, center[1] / 2) + word_centers.append(center) + + for center1 in word_centers: + for center2 in word_centers: + if ( + center1 != center2 + and ( + (center1[0] - center2[0]) ** 2 + (center1[1] - center2[1]) ** 2 + ) + ** 0.5 + <= 400 + ): + centers.append( + ((center1[0] + center2[0]) / 2, (center1[1] + center2[1]) / 2) + ) + break + if centers: + break + + bounding_box_image = Image.fromarray(img_draw) + bounding_box_image.format = img.format + + # Debug by showing bounding boxes: + # bounding_box_image.show() + + return centers, bounding_box_image diff --git a/interpreter/core/utils/html_to_png_base64.py b/interpreter/core/computer/utils/html_to_png_base64.py similarity index 91% rename from interpreter/core/utils/html_to_png_base64.py rename to interpreter/core/computer/utils/html_to_png_base64.py index 1e6e9c8eaf..0452ada5e9 100644 --- a/interpreter/core/utils/html_to_png_base64.py +++ b/interpreter/core/computer/utils/html_to_png_base64.py @@ -5,7 +5,7 @@ from html2image import Html2Image -from ...terminal_interface.utils.local_storage_path import get_storage_path +from ....terminal_interface.utils.local_storage_path import get_storage_path def html_to_png_base64(code): diff --git a/interpreter/core/core.py b/interpreter/core/core.py index 226cd0eb39..29921ea304 100644 --- a/interpreter/core/core.py +++ b/interpreter/core/core.py @@ -10,7 +10,6 @@ from ..terminal_interface.start_terminal_interface import start_terminal_interface from ..terminal_interface.terminal_interface import terminal_interface from ..terminal_interface.utils.get_config import get_config, user_config_path -from ..terminal_interface.utils.in_jupyter_notebook import in_jupyter_notebook from ..terminal_interface.utils.local_storage_path import get_storage_path from .computer.computer import Computer from .generate_system_message import generate_system_message @@ -59,8 +58,10 @@ def __init__(self): # Computer settings self.computer = Computer() - # (Permitted languages, all lowercase) - self.languages = [i.name.lower() for i in self.computer.languages] + # Permitted languages, all lowercase + self.languages = [i.name.lower() for i in self.computer.terminal.languages] + # (Not implemented) Permitted functions + # self.functions = [globals] # OS control mode self.os = False diff --git a/interpreter/core/generate_system_message.py b/interpreter/core/generate_system_message.py index fc7cd30f5e..5ebd598c57 100644 --- a/interpreter/core/generate_system_message.py +++ b/interpreter/core/generate_system_message.py @@ -27,6 +27,7 @@ def generate_system_message(interpreter): try: system_message += "\n" + get_relevant_procedures_string(interpreter) except: + raise if interpreter.debug_mode: print(traceback.format_exc()) # It's okay if they can't. This just fixes some common mistakes it makes. diff --git a/interpreter/core/rag/get_relevant_procedures_string.py b/interpreter/core/rag/get_relevant_procedures_string.py index 940e7555de..e74542dee3 100644 --- a/interpreter/core/rag/get_relevant_procedures_string.py +++ b/interpreter/core/rag/get_relevant_procedures_string.py @@ -13,13 +13,18 @@ def get_relevant_procedures_string(interpreter): ) messages = [{"role": "system", "content": interpreter.system_message}] + messages query = {"query": messages} - url = "https://open-procedures.replit.app/" + url = "https://open-procedures.replit.app/search/" - relevant_procedures = requests.post(url, json=query).json()["procedures"] - relevant_procedures = ( - "[Recommended Procedures]\n" - + "\n---\n".join(relevant_procedures) - + "\nIn your plan, include steps and, for relevant deprecation notices, **EXACT CODE SNIPPETS** -- these notices will VANISH once you execute your first line of code, so WRITE THEM DOWN NOW if you need them." + response = requests.post(url, json=query).json() + + if interpreter.debug_mode: + print(response) + + relevant_procedures = response["procedures"] + relevant_procedures = "[Recommended Procedures]\n" + "\n---\n".join( + relevant_procedures ) + if not interpreter.os and not interpreter.vision: + relevant_procedures += "\nIn your plan, include steps and, for relevant deprecation notices, **EXACT CODE SNIPPETS** -- these notices will VANISH once you execute your first line of code, so WRITE THEM DOWN NOW if you need them." return relevant_procedures diff --git a/interpreter/core/utils/convert_to_openai_messages.py b/interpreter/core/utils/convert_to_openai_messages.py index 82fce9d7a3..72a5fe5f20 100644 --- a/interpreter/core/utils/convert_to_openai_messages.py +++ b/interpreter/core/utils/convert_to_openai_messages.py @@ -113,7 +113,7 @@ def convert_to_openai_messages(messages, function_calling=True, vision=False): "content": [ { "type": "image_url", - "image_url": {"url": content, "detail": "high"}, + "image_url": {"url": content, "detail": "low"}, } ], } diff --git a/interpreter/core/utils/scan_code.py b/interpreter/core/utils/scan_code.py index e16c002cce..49c68846cb 100644 --- a/interpreter/core/utils/scan_code.py +++ b/interpreter/core/utils/scan_code.py @@ -1,12 +1,15 @@ import os import subprocess -from yaspin import yaspin -from yaspin.spinners import Spinners - -from ..computer.computer import language_map +from ..computer.terminal.terminal import language_map from .temporary_file import cleanup_temporary_file, create_temporary_file +try: + from yaspin import yaspin + from yaspin.spinners import Spinners +except ImportError: + pass + def get_language_file_extension(language_name): """ @@ -64,7 +67,7 @@ def scan_code(code, language, interpreter): if scan.returncode == 0: language_name = get_language_name(language) print( - f" {'Code Scaner: ' if interpreter.safe_mode == 'auto' else ''}No issues were found in this {language_name} code." + f" {'Code Scanner: ' if interpreter.safe_mode == 'auto' else ''}No issues were found in this {language_name} code." ) print("") @@ -72,7 +75,7 @@ def scan_code(code, language, interpreter): # and add them to the conversation history except Exception as e: - print(f"Could not scan {language} code.") + print(f"Could not scan {language} code. Have you installed 'semgrep'?") print(e) print("") # <- Aesthetic choice diff --git a/interpreter/terminal_interface/components/code_block.py b/interpreter/terminal_interface/components/code_block.py index 87082f5ce6..8506b9cb36 100644 --- a/interpreter/terminal_interface/components/code_block.py +++ b/interpreter/terminal_interface/components/code_block.py @@ -24,12 +24,18 @@ def __init__(self): self.active_line = None self.margin_top = True + def end(self): + self.active_line = None + self.refresh(cursor=False) + super().end() + def refresh(self, cursor=True): - # Get code, return if there is none - code = self.code - if not code: + if not self.code and not self.output: return + # Get code + code = self.code + # Create a table for the code code_table = Table( show_header=False, show_footer=False, box=None, padding=0, expand=True diff --git a/interpreter/terminal_interface/components/message_block.py b/interpreter/terminal_interface/components/message_block.py index 88895e3326..a7262b735b 100644 --- a/interpreter/terminal_interface/components/message_block.py +++ b/interpreter/terminal_interface/components/message_block.py @@ -1,6 +1,4 @@ -import platform import re -import subprocess from rich.box import MINIMAL from rich.markdown import Markdown @@ -15,8 +13,6 @@ def __init__(self): self.type = "message" self.message = "" - self.has_run = False - self.voice = False def refresh(self, cursor=True): # De-stylize any code blocks in markdown, @@ -31,25 +27,6 @@ def refresh(self, cursor=True): self.live.update(panel) self.live.refresh() - def end(self): - super().end() - if self.voice and platform.system() == "Darwin": - # Just the first and last sentence is read aloud. - message_sentences = re.split(r"(?<=[.!?]) +", self.message) - message = ( - message_sentences[0] + " " + message_sentences[-1] - if len(message_sentences) > 1 - else message_sentences[0] - ) - # Replace newlines with spaces, escape double quotes and backslashes - sanitized_message = ( - message.replace("\\", "\\\\").replace("\n", " ").replace('"', '\\"') - ) - # Use subprocess to make the call non-blocking - subprocess.Popen( - ["osascript", "-e", f'say "{sanitized_message}" using "Fred"'] - ) - def textify_markdown_code_blocks(text): """ diff --git a/interpreter/terminal_interface/render_past_conversation.py b/interpreter/terminal_interface/render_past_conversation.py index 237ff865d4..8867d6fe6b 100644 --- a/interpreter/terminal_interface/render_past_conversation.py +++ b/interpreter/terminal_interface/render_past_conversation.py @@ -1,3 +1,8 @@ +""" +This is all messed up.... Uses the old streaming structure. +""" + + from .components.code_block import CodeBlock from .components.message_block import MessageBlock from .utils.display_markdown_message import display_markdown_message diff --git a/interpreter/terminal_interface/start_terminal_interface.py b/interpreter/terminal_interface/start_terminal_interface.py index f36bcd5ef4..4a0df5e129 100644 --- a/interpreter/terminal_interface/start_terminal_interface.py +++ b/interpreter/terminal_interface/start_terminal_interface.py @@ -1,6 +1,7 @@ import argparse import os import platform +import re import subprocess import sys @@ -294,53 +295,89 @@ def start_terminal_interface(interpreter): if args.os: interpreter.os = True + interpreter.disable_procedures = True interpreter.vision = True - # interpreter.model = "gpt-4-vision-preview" + interpreter.model = "gpt-4-vision-preview" interpreter.function_calling_llm = False interpreter.context_window = 110000 interpreter.max_tokens = 4096 interpreter.auto_run = True interpreter.force_task_completion = True - interpreter.system_message += """\nIf you use `plt.show()`, the resulting image will be sent to you. However, if you use `PIL.Image.show()`, the resulting image will NOT be sent to you. The user has enabled OS control. They have given you permission to execute any code to control their mouse and keyboard to complete the task.""" + interpreter.system_message += ( + "\n\n" + + """ + +Execute code using `computer` (already imported) to control the user's computer: + +```python +computer.screenshot() # Automatically runs plt.show() to show you what's on the screen, returns a PIL image in case you need it (rarely). **You almost always want to do this first! You don't know what's on the user's screen.** +computer.screenshot(quadrant=1) # Get a detailed view of the upper left quadrant + +computer.keyboard(" ", modifiers=['command']) # Opens spotlight + +computer.mouse.move("Text in a button") # This finds the button with that text +computer.mouse.move(x=0, y=0) # Not as accurate as click("Text")! +computer.mouse.move(icon="gear") # Attempts to find the gear icon. Very slow +computer.mouse.click() # Don't forget this! Include in the same code block + +# Dragging +computer.mouse.down() +computer.mouse.move(x=100, y=100) +computer.mouse.up() + +computer.clipboard.copy() +print(computer.clipboard.read()) # Returns contents of clipboard +``` + +For rare and complex mouse actions, consider using computer vision libraries on `pil_image` to produce a list of coordinates for the mouse to move/drag to. + +**Use keyboard navigation as much as possible.** The mouse is less reliable. + +If you use `plt.show()`, the resulting image will be sent to you. However, if you use `PIL.Image.show()`, the resulting image will NOT be sent to you. + +The user has enabled OS control. They have given you permission to execute any code to control their mouse and keyboard to complete the task. + + """.strip() + ) # Download required packages try: import cv2 import IPython - import languagetools import matplotlib import pyautogui import pytesseract except ImportError: display_markdown_message( - "**Missing packages.** Several packages (e.g. `pyautogui`, `matplotlib`) are required for OS Control. Can we install them?" + "> **Missing Packages**\n\nSeveral packages are required for OS Control (`matplotlib`, `pytesseract`, `pyautogui`, `opencv-python`, `ipython`).\n\nInstall them?\n" ) user_input = input("(y/n) > ") if user_input.lower() != "y": + print("Exiting...") return - packages = [ - "matplotlib", - "pytesseract", - "pyautogui", - "languagetools", - "opencv-python", - "ipython", + install_commands = [ + "pip install matplotlib", + "pip install pytesseract", + "pip install pyautogui", + "pip install opencv-python", + "pip install ipython", ] - install_commands = "import pip\n" - for package in packages: - install_commands += f"pip.main(['install', '--upgrade', '{package}'])\n" - interpreter.computer.run("python", install_commands) + command = "\n".join(install_commands) + for chunk in interpreter.computer.run("shell", command): + if chunk.get("format") != "active_line": + print(chunk.get("content")) display_markdown_message( "> `OS Control` enabled (experimental)\n\n**Warning:** In this mode, Open Interpreter will **not** require approval before performing actions. Be ready to close your terminal." ) print("") - # Run imports so it doesnt have to - interpreter.computer.run( + # Give it access to the computer via Python + for _ in interpreter.computer.run( "python", - "import pyautogui\nimport matplotlib\nimport languagetools as lt\nimport pytesseract\nimport cv2", - ) + "import interpreter\ncomputer = interpreter.computer", + ): + pass if not interpreter.local and interpreter.model == "gpt-4-1106-preview": if interpreter.context_window is None: diff --git a/interpreter/terminal_interface/terminal_interface.py b/interpreter/terminal_interface/terminal_interface.py index 17fd7de711..b0a9fe79bc 100644 --- a/interpreter/terminal_interface/terminal_interface.py +++ b/interpreter/terminal_interface/terminal_interface.py @@ -8,6 +8,9 @@ except ImportError: pass +import platform +import re +import subprocess import time from ..core.utils.scan_code import scan_code @@ -58,7 +61,14 @@ def terminal_interface(interpreter, message): else: interactive = True - just_pressed_ctrl_c = False + pause_force_task_completion_loop = False + force_task_completion_message = "Proceed. If the entire task I asked for is done, say exactly 'The task is done.' If it's impossible, say 'The task is impossible.' (If I haven't provided a task, say exactly 'Let me know what you'd like to do next.') Otherwise keep going." + force_task_completion_responses = [ + "the task is done.", + "the task is impossible.", + "let me know what you'd like to do next.", + ] + voice_subprocess = None while True: try: @@ -67,20 +77,15 @@ def terminal_interface(interpreter, message): ### I think `force_task_completion` should be moved to the core. # `force_task_completion` makes it utter specific phrases if it doesn't want to be told to "Proceed." if ( - not just_pressed_ctrl_c + not pause_force_task_completion_loop and interpreter.force_task_completion and interpreter.messages and not any( task_status in interpreter.messages[-1].get("content", "").lower() - for task_status in [ - "the task is done.", - "the task is impossible.", - "you haven't provided a task.", - ] + for task_status in force_task_completion_responses ) ): - force_task_completion_message = "Proceed. If the entire task is done, say exactly 'The task is done.' If it's impossible, say 'The task is impossible.' (If I haven't provided a task, say exactly 'You haven't provided a task.') Otherwise keep going." # Remove past force_task_completion messages interpreter.messages = [ message @@ -109,7 +114,7 @@ def terminal_interface(interpreter, message): ### This is the primary input for Open Interpreter. message = input("> ").strip() - just_pressed_ctrl_c = False # Just used for `interpreter.force_task_completion`, to escape the loop above^ + pause_force_task_completion_loop = False # Just used for `interpreter.force_task_completion`, to escape the loop above^ try: # This lets users hit the up arrow key for past messages @@ -130,6 +135,7 @@ def terminal_interface(interpreter, message): if message.startswith("%") and interactive: handle_magic_command(interpreter, message) + pause_force_task_completion_loop = True continue # Many users do this @@ -190,14 +196,46 @@ def terminal_interface(interpreter, message): if chunk["type"] == "message": if "start" in chunk: active_block = MessageBlock() - if interpreter.os: - # OS mode uses voice — otherwise you can't tell what it's doing! - active_block.voice = True render_cursor = True if "content" in chunk: active_block.message += chunk["content"] + if "end" in chunk and interpreter.os: + last_message = interpreter.messages[-1]["content"] + if ( + platform.system() == "Darwin" + and last_message not in force_task_completion_responses + ): + # Remove markdown lists and the line above markdown lists + lines = last_message.split("\n") + i = 0 + while i < len(lines): + # Match markdown lists starting with hyphen, asterisk or number + if re.match(r"^\s*([-*]|\d+\.)\s", lines[i]): + del lines[i] + if i > 0: + del lines[i - 1] + i -= 1 + else: + i += 1 + message = "\n".join(lines) + # Replace newlines with spaces, escape double quotes and backslashes + sanitized_message = ( + message.replace("\\", "\\\\") + .replace("\n", " ") + .replace('"', '\\"') + ) + if voice_subprocess: + voice_subprocess.terminate() + voice_subprocess = subprocess.Popen( + [ + "osascript", + "-e", + f'say "{sanitized_message}" using "Fred"', + ] + ) + # Assistant code blocks elif chunk["role"] == "assistant" and chunk["type"] == "code": if "start" in chunk: diff --git a/poetry.lock b/poetry.lock index 986088b267..80dd80348d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "aiohttp" @@ -110,6 +110,17 @@ files = [ [package.dependencies] frozenlist = ">=1.1.0" +[[package]] +name = "annotated-types" +version = "0.6.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, + {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, +] + [[package]] name = "ansicon" version = "1.89.0" @@ -259,6 +270,80 @@ jinxed = {version = ">=1.1.0", markers = "platform_system == \"Windows\""} six = ">=1.9.0" wcwidth = ">=0.1.4" +[[package]] +name = "boltons" +version = "21.0.0" +description = "When they're not builtins, they're boltons." +optional = true +python-versions = "*" +files = [ + {file = "boltons-21.0.0-py2.py3-none-any.whl", hash = "sha256:b9bb7b58b2b420bbe11a6025fdef6d3e5edc9f76a42fb467afe7ca212ef9948b"}, + {file = "boltons-21.0.0.tar.gz", hash = "sha256:65e70a79a731a7fe6e98592ecfb5ccf2115873d01dbc576079874629e5c90f13"}, +] + +[[package]] +name = "bracex" +version = "2.4" +description = "Bash style brace expander." +optional = true +python-versions = ">=3.8" +files = [ + {file = "bracex-2.4-py3-none-any.whl", hash = "sha256:efdc71eff95eaff5e0f8cfebe7d01adf2c8637c8c92edaf63ef348c241a82418"}, + {file = "bracex-2.4.tar.gz", hash = "sha256:a27eaf1df42cf561fed58b7a8f3fdf129d1ea16a81e1fadd1d17989bc6384beb"}, +] + +[[package]] +name = "cairocffi" +version = "1.6.1" +description = "cffi-based cairo bindings for Python" +optional = true +python-versions = ">=3.7" +files = [ + {file = "cairocffi-1.6.1-py3-none-any.whl", hash = "sha256:aa78ee52b9069d7475eeac457389b6275aa92111895d78fbaa2202a52dac112e"}, + {file = "cairocffi-1.6.1.tar.gz", hash = "sha256:78e6bbe47357640c453d0be929fa49cd05cce2e1286f3d2a1ca9cbda7efdb8b7"}, +] + +[package.dependencies] +cffi = ">=1.1.0" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "numpy", "pikepdf", "pytest"] +xcb = ["xcffib (>=1.4.0)"] + +[[package]] +name = "cairosvg" +version = "2.7.1" +description = "A Simple SVG Converter based on Cairo" +optional = true +python-versions = ">=3.5" +files = [ + {file = "CairoSVG-2.7.1-py3-none-any.whl", hash = "sha256:8a5222d4e6c3f86f1f7046b63246877a63b49923a1cd202184c3a634ef546b3b"}, + {file = "CairoSVG-2.7.1.tar.gz", hash = "sha256:432531d72347291b9a9ebfb6777026b607563fd8719c46ee742db0aef7271ba0"}, +] + +[package.dependencies] +cairocffi = "*" +cssselect2 = "*" +defusedxml = "*" +pillow = "*" +tinycss2 = "*" + +[package.extras] +doc = ["sphinx", "sphinx-rtd-theme"] +test = ["flake8", "isort", "pytest"] + +[[package]] +name = "cerberus" +version = "1.3.5" +description = "Lightweight, extensible schema and data validation tool for Pythondictionaries." +optional = false +python-versions = "*" +files = [ + {file = "Cerberus-1.3.5-py3-none-any.whl", hash = "sha256:7649a5815024d18eb7c6aa5e7a95355c649a53aacfc9b050e9d0bf6bfa2af372"}, + {file = "Cerberus-1.3.5.tar.gz", hash = "sha256:81011e10266ef71b6ec6d50e60171258a5b134d69f8fb387d16e4936d0d47642"}, +] + [[package]] name = "certifi" version = "2023.11.17" @@ -458,6 +543,25 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "click-option-group" +version = "0.5.6" +description = "Option groups missing in Click" +optional = true +python-versions = ">=3.6,<4" +files = [ + {file = "click-option-group-0.5.6.tar.gz", hash = "sha256:97d06703873518cc5038509443742b25069a3c7562d1ea72ff08bfadde1ce777"}, + {file = "click_option_group-0.5.6-py3-none-any.whl", hash = "sha256:38a26d963ee3ad93332ddf782f9259c5bdfe405e73408d943ef5e7d0c3767ec7"}, +] + +[package.dependencies] +Click = ">=7.0,<9" + +[package.extras] +docs = ["Pallets-Sphinx-Themes", "m2r2", "sphinx"] +tests = ["pytest"] +tests-cov = ["coverage", "coveralls", "pytest", "pytest-cov"] + [[package]] name = "colorama" version = "0.4.6" @@ -549,6 +653,25 @@ mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.6.1)", "types-Pill test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] +[[package]] +name = "cssselect2" +version = "0.7.0" +description = "CSS selectors for Python ElementTree" +optional = true +python-versions = ">=3.7" +files = [ + {file = "cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969"}, + {file = "cssselect2-0.7.0.tar.gz", hash = "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a"}, +] + +[package.dependencies] +tinycss2 = "*" +webencodings = "*" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + [[package]] name = "cycler" version = "0.12.1" @@ -602,6 +725,17 @@ files = [ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = true +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + [[package]] name = "distlib" version = "0.3.7" @@ -613,6 +747,16 @@ files = [ {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, ] +[[package]] +name = "docopt" +version = "0.6.2" +description = "Pythonic argument parser, that will make you smile" +optional = false +python-versions = "*" +files = [ + {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, +] + [[package]] name = "exceptiongroup" version = "1.2.0" @@ -641,6 +785,20 @@ files = [ [package.extras] tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +[[package]] +name = "face" +version = "22.0.0" +description = "A command-line application framework (and CLI parser). Friendly for users, full-featured for developers." +optional = true +python-versions = "*" +files = [ + {file = "face-22.0.0-py3-none-any.whl", hash = "sha256:344fe31562d0f6f444a45982418f3793d4b14f9abb98ccca1509d22e0a3e7e35"}, + {file = "face-22.0.0.tar.gz", hash = "sha256:d5d692f90bc8f5987b636e47e36384b9bbda499aaf0a77aa0b0bbe834c76923d"}, +] + +[package.dependencies] +boltons = ">=20.0.0" + [[package]] name = "filelock" version = "3.13.1" @@ -872,6 +1030,25 @@ gitdb = ">=4.0.1,<5" [package.extras] test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-instafail", "pytest-subtests", "pytest-sugar"] +[[package]] +name = "glom" +version = "22.1.0" +description = "A declarative object transformer and formatter, for conglomerating nested data." +optional = true +python-versions = "*" +files = [ + {file = "glom-22.1.0-py2.py3-none-any.whl", hash = "sha256:5339da206bf3532e01a83a35aca202960ea885156986d190574b779598e9e772"}, + {file = "glom-22.1.0.tar.gz", hash = "sha256:1510c6587a8f9c64a246641b70033cbc5ebde99f02ad245693678038e821aeb5"}, +] + +[package.dependencies] +attrs = "*" +boltons = ">=19.3.0" +face = ">=20.1.0" + +[package.extras] +yaml = ["PyYAML"] + [[package]] name = "html2image" version = "2.0.4.3" @@ -1062,20 +1239,23 @@ test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pa [[package]] name = "isort" -version = "5.12.0" +version = "5.13.0" description = "A Python utility / library to sort Python imports." optional = false python-versions = ">=3.8.0" files = [ - {file = "isort-5.12.0-py3-none-any.whl", hash = "sha256:f84c2818376e66cf843d497486ea8fed8700b340f308f076c6fb1229dff318b6"}, - {file = "isort-5.12.0.tar.gz", hash = "sha256:8bef7dde241278824a6d83f44a544709b065191b95b6e50894bdc722fcba0504"}, + {file = "isort-5.13.0-py3-none-any.whl", hash = "sha256:15e0e937819b350bc256a7ae13bb25f4fe4f8871a0bc335b20c3627dba33f458"}, + {file = "isort-5.13.0.tar.gz", hash = "sha256:d67f78c6a1715f224cca46b29d740037bdb6eea15323a133e897cda15876147b"}, ] +[package.dependencies] +pip-api = "*" +pipreqs = "*" +requirementslib = "*" + [package.extras] -colors = ["colorama (>=0.4.3)"] -pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +colors = ["colorama (>=0.4.6)"] plugins = ["setuptools"] -requirements-deprecated-finder = ["pip-api", "pipreqs"] [[package]] name = "jedi" @@ -1127,6 +1307,41 @@ files = [ [package.dependencies] ansicon = {version = "*", markers = "platform_system == \"Windows\""} +[[package]] +name = "jsonschema" +version = "4.20.0" +description = "An implementation of JSON Schema validation for Python" +optional = true +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.20.0-py3-none-any.whl", hash = "sha256:ed6231f0429ecf966f5bc8dfef245998220549cbbcf140f913b7464c52c3b6b3"}, + {file = "jsonschema-4.20.0.tar.gz", hash = "sha256:4f614fd46d8d61258610998997743ec5492a648b33cf478c1ddc23ed4598a5fa"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.11.2" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = true +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.11.2-py3-none-any.whl", hash = "sha256:e74ba7c0a65e8cb49dc26837d6cfe576557084a8b423ed16a420984228104f93"}, + {file = "jsonschema_specifications-2023.11.2.tar.gz", hash = "sha256:9472fc4fea474cd74bea4a2b190daeccb5a9e4db2ea80efcf7a1b582fc9a81b8"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + [[package]] name = "jupyter-client" version = "8.6.0" @@ -1470,6 +1685,21 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] +[[package]] +name = "mouseinfo" +version = "0.1.3" +description = "An application to display XY position and RGB color information for the pixel currently under the mouse. Works on Python 2 and 3." +optional = true +python-versions = "*" +files = [ + {file = "MouseInfo-0.1.3.tar.gz", hash = "sha256:2c62fb8885062b8e520a3cce0a297c657adcc08c60952eb05bc8256ef6f7f6e7"}, +] + +[package.dependencies] +pyperclip = "*" +python3-Xlib = {version = "*", markers = "platform_system == \"Linux\" and python_version >= \"3.0\""} +rubicon-objc = {version = "*", markers = "platform_system == \"Darwin\""} + [[package]] name = "multidict" version = "6.0.4" @@ -1656,6 +1886,29 @@ dev = ["black (>=21.6b0,<22.0)", "pytest (==6.*)", "pytest-asyncio", "pytest-moc embeddings = ["matplotlib", "numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "plotly", "scikit-learn (>=1.0.2)", "scipy", "tenacity (>=8.0.1)"] wandb = ["numpy", "openpyxl (>=3.0.7)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)", "wandb"] +[[package]] +name = "opencv-python" +version = "4.8.1.78" +description = "Wrapper package for OpenCV python bindings." +optional = true +python-versions = ">=3.6" +files = [ + {file = "opencv-python-4.8.1.78.tar.gz", hash = "sha256:cc7adbbcd1112877a39274106cb2752e04984bc01a031162952e97450d6117f6"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-macosx_10_16_x86_64.whl", hash = "sha256:91d5f6f5209dc2635d496f6b8ca6573ecdad051a09e6b5de4c399b8e673c60da"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:bc31f47e05447da8b3089faa0a07ffe80e114c91ce0b171e6424f9badbd1c5cd"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9814beca408d3a0eca1bae7e3e5be68b07c17ecceb392b94170881216e09b319"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c4c406bdb41eb21ea51b4e90dfbc989c002786c3f601c236a99c59a54670a394"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-win32.whl", hash = "sha256:a7aac3900fbacf55b551e7b53626c3dad4c71ce85643645c43e91fcb19045e47"}, + {file = "opencv_python-4.8.1.78-cp37-abi3-win_amd64.whl", hash = "sha256:b983197f97cfa6fcb74e1da1802c7497a6f94ed561aba6980f1f33123f904956"}, +] + +[package.dependencies] +numpy = [ + {version = ">=1.23.5", markers = "python_version >= \"3.11\""}, + {version = ">=1.21.4", markers = "python_version >= \"3.10\" and platform_system == \"Darwin\" and python_version < \"3.11\""}, + {version = ">=1.21.2", markers = "platform_system != \"Darwin\" and python_version >= \"3.10\" and python_version < \"3.11\""}, +] + [[package]] name = "packaging" version = "23.2" @@ -1684,15 +1937,39 @@ testing = ["docopt", "pytest (<6.0.0)"] [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.0" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.0-py3-none-any.whl", hash = "sha256:f1f8a7eab698c357945c85ed79715e014612b8584faebe209dca4558e2b09513"}, + {file = "pathspec-0.12.0.tar.gz", hash = "sha256:c57e16065a97b7beb175f13c84d27cb05f7b7315741c2fbd5de541042f4ea6e1"}, +] + +[[package]] +name = "peewee" +version = "3.17.0" +description = "a little orm" +optional = true +python-versions = "*" +files = [ + {file = "peewee-3.17.0.tar.gz", hash = "sha256:3a56967f28a43ca7a4287f4803752aeeb1a57a08dee2e839b99868181dfb5df8"}, +] + +[[package]] +name = "pep517" +version = "0.13.1" +description = "Wrappers to build Python packages using PEP 517 hooks" +optional = false +python-versions = ">=3.6" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pep517-0.13.1-py3-none-any.whl", hash = "sha256:31b206f67165b3536dd577c5c3f1518e8fbaf38cbc57efff8369a392feff1721"}, + {file = "pep517-0.13.1.tar.gz", hash = "sha256:1b2fa2ffd3938bb4beffe5d6146cbcb2bda996a5a4da9f31abffd8b24e07b317"}, ] +[package.dependencies] +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + [[package]] name = "pexpect" version = "4.9.0" @@ -1774,6 +2051,46 @@ files = [ docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +[[package]] +name = "pip" +version = "23.3.1" +description = "The PyPA recommended tool for installing Python packages." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pip-23.3.1-py3-none-any.whl", hash = "sha256:55eb67bb6171d37447e82213be585b75fe2b12b359e993773aca4de9247a052b"}, + {file = "pip-23.3.1.tar.gz", hash = "sha256:1fcaa041308d01f14575f6d0d2ea4b75a3e2871fe4f9c694976f908768e14174"}, +] + +[[package]] +name = "pip-api" +version = "0.0.30" +description = "An unofficial, importable pip API" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pip-api-0.0.30.tar.gz", hash = "sha256:a05df2c7aa9b7157374bcf4273544201a0c7bae60a9c65bcf84f3959ef3896f3"}, + {file = "pip_api-0.0.30-py3-none-any.whl", hash = "sha256:2a0314bd31522eb9ffe8a99668b0d07fee34ebc537931e7b6483001dbedcbdc9"}, +] + +[package.dependencies] +pip = "*" + +[[package]] +name = "pipreqs" +version = "0.4.13" +description = "Pip requirements.txt generator based on imports in project" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pipreqs-0.4.13-py2.py3-none-any.whl", hash = "sha256:e522b9ed54aa3e8b7978ff251ab7a9af2f75d2cd8de4c102e881b666a79a308e"}, + {file = "pipreqs-0.4.13.tar.gz", hash = "sha256:a17f167880b6921be37533ce4c81ddc6e22b465c107aad557db43b1add56a99b"}, +] + +[package.dependencies] +docopt = "*" +yarg = "*" + [[package]] name = "platformdirs" version = "4.1.0" @@ -1789,6 +2106,25 @@ files = [ docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +[[package]] +name = "plette" +version = "0.4.4" +description = "Structured Pipfile and Pipfile.lock models." +optional = false +python-versions = ">=3.7" +files = [ + {file = "plette-0.4.4-py2.py3-none-any.whl", hash = "sha256:42d68ce8c6b966874b68758d87d7f20fcff2eff0d861903eea1062126be4d98f"}, + {file = "plette-0.4.4.tar.gz", hash = "sha256:06b8c09eb90293ad0b8101cb5c95c4ea53e9b2b582901845d0904ff02d237454"}, +] + +[package.dependencies] +cerberus = {version = "*", optional = true, markers = "extra == \"validation\""} +tomlkit = "*" + +[package.extras] +tests = ["pytest", "pytest-cov", "pytest-xdist"] +validation = ["cerberus"] + [[package]] name = "pluggy" version = "1.3.0" @@ -1806,13 +2142,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "3.5.0" +version = "3.6.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"}, - {file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"}, + {file = "pre_commit-3.6.0-py2.py3-none-any.whl", hash = "sha256:c255039ef399049a5544b6ce13d135caba8f2c28c3b4033277a788f434308376"}, + {file = "pre_commit-3.6.0.tar.gz", hash = "sha256:d30bad9abf165f7785c15a21a1f46da7d0677cb00ee7ff4c579fd38922efe15d"}, ] [package.dependencies] @@ -1889,6 +2225,26 @@ files = [ [package.extras] tests = ["pytest"] +[[package]] +name = "pyautogui" +version = "0.9.54" +description = "PyAutoGUI lets Python control the mouse and keyboard, and other GUI automation tasks. For Windows, macOS, and Linux, on Python 3 and 2." +optional = true +python-versions = "*" +files = [ + {file = "PyAutoGUI-0.9.54.tar.gz", hash = "sha256:dd1d29e8fd118941cb193f74df57e5c6ff8e9253b99c7b04f39cfc69f3ae04b2"}, +] + +[package.dependencies] +mouseinfo = "*" +pygetwindow = ">=0.0.5" +pymsgbox = "*" +pyobjc-core = {version = "*", markers = "platform_system == \"Darwin\""} +pyobjc-framework-quartz = {version = "*", markers = "platform_system == \"Darwin\""} +pyscreeze = ">=0.1.21" +python3-Xlib = {version = "*", markers = "platform_system == \"Linux\" and python_version >= \"3.0\""} +pytweening = ">=1.0.4" + [[package]] name = "pycparser" version = "2.21" @@ -1900,6 +2256,155 @@ files = [ {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, ] +[[package]] +name = "pydantic" +version = "2.5.2" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic-2.5.2-py3-none-any.whl", hash = "sha256:80c50fb8e3dcecfddae1adbcc00ec5822918490c99ab31f6cf6140ca1c1429f0"}, + {file = "pydantic-2.5.2.tar.gz", hash = "sha256:ff177ba64c6faf73d7afa2e8cad38fd456c0dbe01c9954e71038001cd15a6edd"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.14.5" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.14.5" +description = "" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:7e88f5696153dc516ba6e79f82cc4747e87027205f0e02390c21f7cb3bd8abfd"}, + {file = "pydantic_core-2.14.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4641e8ad4efb697f38a9b64ca0523b557c7931c5f84e0fd377a9a3b05121f0de"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:774de879d212db5ce02dfbf5b0da9a0ea386aeba12b0b95674a4ce0593df3d07"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ebb4e035e28f49b6f1a7032920bb9a0c064aedbbabe52c543343d39341a5b2a3"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b53e9ad053cd064f7e473a5f29b37fc4cc9dc6d35f341e6afc0155ea257fc911"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8aa1768c151cf562a9992462239dfc356b3d1037cc5a3ac829bb7f3bda7cc1f9"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac5c82fc632c599f4639a5886f96867ffced74458c7db61bc9a66ccb8ee3113"}, + {file = "pydantic_core-2.14.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2ae91f50ccc5810b2f1b6b858257c9ad2e08da70bf890dee02de1775a387c66"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6b9ff467ffbab9110e80e8c8de3bcfce8e8b0fd5661ac44a09ae5901668ba997"}, + {file = "pydantic_core-2.14.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:61ea96a78378e3bd5a0be99b0e5ed00057b71f66115f5404d0dae4819f495093"}, + {file = "pydantic_core-2.14.5-cp310-none-win32.whl", hash = "sha256:bb4c2eda937a5e74c38a41b33d8c77220380a388d689bcdb9b187cf6224c9720"}, + {file = "pydantic_core-2.14.5-cp310-none-win_amd64.whl", hash = "sha256:b7851992faf25eac90bfcb7bfd19e1f5ffa00afd57daec8a0042e63c74a4551b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:4e40f2bd0d57dac3feb3a3aed50f17d83436c9e6b09b16af271b6230a2915459"}, + {file = "pydantic_core-2.14.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ab1cdb0f14dc161ebc268c09db04d2c9e6f70027f3b42446fa11c153521c0e88"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aae7ea3a1c5bb40c93cad361b3e869b180ac174656120c42b9fadebf685d121b"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:60b7607753ba62cf0739177913b858140f11b8af72f22860c28eabb2f0a61937"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2248485b0322c75aee7565d95ad0e16f1c67403a470d02f94da7344184be770f"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:823fcc638f67035137a5cd3f1584a4542d35a951c3cc68c6ead1df7dac825c26"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96581cfefa9123accc465a5fd0cc833ac4d75d55cc30b633b402e00e7ced00a6"}, + {file = "pydantic_core-2.14.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a33324437018bf6ba1bb0f921788788641439e0ed654b233285b9c69704c27b4"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9bd18fee0923ca10f9a3ff67d4851c9d3e22b7bc63d1eddc12f439f436f2aada"}, + {file = "pydantic_core-2.14.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:853a2295c00f1d4429db4c0fb9475958543ee80cfd310814b5c0ef502de24dda"}, + {file = "pydantic_core-2.14.5-cp311-none-win32.whl", hash = "sha256:cb774298da62aea5c80a89bd58c40205ab4c2abf4834453b5de207d59d2e1651"}, + {file = "pydantic_core-2.14.5-cp311-none-win_amd64.whl", hash = "sha256:e87fc540c6cac7f29ede02e0f989d4233f88ad439c5cdee56f693cc9c1c78077"}, + {file = "pydantic_core-2.14.5-cp311-none-win_arm64.whl", hash = "sha256:57d52fa717ff445cb0a5ab5237db502e6be50809b43a596fb569630c665abddf"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:e60f112ac88db9261ad3a52032ea46388378034f3279c643499edb982536a093"}, + {file = "pydantic_core-2.14.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6e227c40c02fd873c2a73a98c1280c10315cbebe26734c196ef4514776120aeb"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0cbc7fff06a90bbd875cc201f94ef0ee3929dfbd5c55a06674b60857b8b85ed"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:103ef8d5b58596a731b690112819501ba1db7a36f4ee99f7892c40da02c3e189"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c949f04ecad823f81b1ba94e7d189d9dfb81edbb94ed3f8acfce41e682e48cef"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c1452a1acdf914d194159439eb21e56b89aa903f2e1c65c60b9d874f9b950e5d"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cb4679d4c2b089e5ef89756bc73e1926745e995d76e11925e3e96a76d5fa51fc"}, + {file = "pydantic_core-2.14.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cf9d3fe53b1ee360e2421be95e62ca9b3296bf3f2fb2d3b83ca49ad3f925835e"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:70f4b4851dbb500129681d04cc955be2a90b2248d69273a787dda120d5cf1f69"}, + {file = "pydantic_core-2.14.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:59986de5710ad9613ff61dd9b02bdd2f615f1a7052304b79cc8fa2eb4e336d2d"}, + {file = "pydantic_core-2.14.5-cp312-none-win32.whl", hash = "sha256:699156034181e2ce106c89ddb4b6504c30db8caa86e0c30de47b3e0654543260"}, + {file = "pydantic_core-2.14.5-cp312-none-win_amd64.whl", hash = "sha256:5baab5455c7a538ac7e8bf1feec4278a66436197592a9bed538160a2e7d11e36"}, + {file = "pydantic_core-2.14.5-cp312-none-win_arm64.whl", hash = "sha256:e47e9a08bcc04d20975b6434cc50bf82665fbc751bcce739d04a3120428f3e27"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_10_7_x86_64.whl", hash = "sha256:af36f36538418f3806048f3b242a1777e2540ff9efaa667c27da63d2749dbce0"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-macosx_11_0_arm64.whl", hash = "sha256:45e95333b8418ded64745f14574aa9bfc212cb4fbeed7a687b0c6e53b5e188cd"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e47a76848f92529879ecfc417ff88a2806438f57be4a6a8bf2961e8f9ca9ec7"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d81e6987b27bc7d101c8597e1cd2bcaa2fee5e8e0f356735c7ed34368c471550"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:34708cc82c330e303f4ce87758828ef6e457681b58ce0e921b6e97937dd1e2a3"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:652c1988019752138b974c28f43751528116bcceadad85f33a258869e641d753"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e4d090e73e0725b2904fdbdd8d73b8802ddd691ef9254577b708d413bf3006e"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c7d5b5005f177764e96bd584d7bf28d6e26e96f2a541fdddb934c486e36fd59"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a71891847f0a73b1b9eb86d089baee301477abef45f7eaf303495cd1473613e4"}, + {file = "pydantic_core-2.14.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a717aef6971208f0851a2420b075338e33083111d92041157bbe0e2713b37325"}, + {file = "pydantic_core-2.14.5-cp37-none-win32.whl", hash = "sha256:de790a3b5aa2124b8b78ae5faa033937a72da8efe74b9231698b5a1dd9be3405"}, + {file = "pydantic_core-2.14.5-cp37-none-win_amd64.whl", hash = "sha256:6c327e9cd849b564b234da821236e6bcbe4f359a42ee05050dc79d8ed2a91588"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:ef98ca7d5995a82f43ec0ab39c4caf6a9b994cb0b53648ff61716370eadc43cf"}, + {file = "pydantic_core-2.14.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c6eae413494a1c3f89055da7a5515f32e05ebc1a234c27674a6956755fb2236f"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcf4e6d85614f7a4956c2de5a56531f44efb973d2fe4a444d7251df5d5c4dcfd"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6637560562134b0e17de333d18e69e312e0458ee4455bdad12c37100b7cad706"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:77fa384d8e118b3077cccfcaf91bf83c31fe4dc850b5e6ee3dc14dc3d61bdba1"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16e29bad40bcf97aac682a58861249ca9dcc57c3f6be22f506501833ddb8939c"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:531f4b4252fac6ca476fbe0e6f60f16f5b65d3e6b583bc4d87645e4e5ddde331"}, + {file = "pydantic_core-2.14.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:074f3d86f081ce61414d2dc44901f4f83617329c6f3ab49d2bc6c96948b2c26b"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:c2adbe22ab4babbca99c75c5d07aaf74f43c3195384ec07ccbd2f9e3bddaecec"}, + {file = "pydantic_core-2.14.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:0f6116a558fd06d1b7c2902d1c4cf64a5bd49d67c3540e61eccca93f41418124"}, + {file = "pydantic_core-2.14.5-cp38-none-win32.whl", hash = "sha256:fe0a5a1025eb797752136ac8b4fa21aa891e3d74fd340f864ff982d649691867"}, + {file = "pydantic_core-2.14.5-cp38-none-win_amd64.whl", hash = "sha256:079206491c435b60778cf2b0ee5fd645e61ffd6e70c47806c9ed51fc75af078d"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:a6a16f4a527aae4f49c875da3cdc9508ac7eef26e7977952608610104244e1b7"}, + {file = "pydantic_core-2.14.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:abf058be9517dc877227ec3223f0300034bd0e9f53aebd63cf4456c8cb1e0863"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49b08aae5013640a3bfa25a8eebbd95638ec3f4b2eaf6ed82cf0c7047133f03b"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c2d97e906b4ff36eb464d52a3bc7d720bd6261f64bc4bcdbcd2c557c02081ed2"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3128e0bbc8c091ec4375a1828d6118bc20404883169ac95ffa8d983b293611e6"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88e74ab0cdd84ad0614e2750f903bb0d610cc8af2cc17f72c28163acfcf372a4"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c339dabd8ee15f8259ee0f202679b6324926e5bc9e9a40bf981ce77c038553db"}, + {file = "pydantic_core-2.14.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3387277f1bf659caf1724e1afe8ee7dbc9952a82d90f858ebb931880216ea955"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ba6b6b3846cfc10fdb4c971980a954e49d447cd215ed5a77ec8190bc93dd7bc5"}, + {file = "pydantic_core-2.14.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca61d858e4107ce5e1330a74724fe757fc7135190eb5ce5c9d0191729f033209"}, + {file = "pydantic_core-2.14.5-cp39-none-win32.whl", hash = "sha256:ec1e72d6412f7126eb7b2e3bfca42b15e6e389e1bc88ea0069d0cc1742f477c6"}, + {file = "pydantic_core-2.14.5-cp39-none-win_amd64.whl", hash = "sha256:c0b97ec434041827935044bbbe52b03d6018c2897349670ff8fe11ed24d1d4ab"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:79e0a2cdbdc7af3f4aee3210b1172ab53d7ddb6a2d8c24119b5706e622b346d0"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:678265f7b14e138d9a541ddabbe033012a2953315739f8cfa6d754cc8063e8ca"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95b15e855ae44f0c6341ceb74df61b606e11f1087e87dcb7482377374aac6abe"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:09b0e985fbaf13e6b06a56d21694d12ebca6ce5414b9211edf6f17738d82b0f8"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3ad873900297bb36e4b6b3f7029d88ff9829ecdc15d5cf20161775ce12306f8a"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2d0ae0d8670164e10accbeb31d5ad45adb71292032d0fdb9079912907f0085f4"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:d37f8ec982ead9ba0a22a996129594938138a1503237b87318392a48882d50b7"}, + {file = "pydantic_core-2.14.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:35613015f0ba7e14c29ac6c2483a657ec740e5ac5758d993fdd5870b07a61d8b"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab4ea451082e684198636565224bbb179575efc1658c48281b2c866bfd4ddf04"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ce601907e99ea5b4adb807ded3570ea62186b17f88e271569144e8cca4409c7"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb2ed8b3fe4bf4506d6dab3b93b83bbc22237e230cba03866d561c3577517d18"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:70f947628e074bb2526ba1b151cee10e4c3b9670af4dbb4d73bc8a89445916b5"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:4bc536201426451f06f044dfbf341c09f540b4ebdb9fd8d2c6164d733de5e634"}, + {file = "pydantic_core-2.14.5-pp37-pypy37_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f4791cf0f8c3104ac668797d8c514afb3431bc3305f5638add0ba1a5a37e0d88"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:038c9f763e650712b899f983076ce783175397c848da04985658e7628cbe873b"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:27548e16c79702f1e03f5628589c6057c9ae17c95b4c449de3c66b589ead0520"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97bee68898f3f4344eb02fec316db93d9700fb1e6a5b760ffa20d71d9a46ce3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b759b77f5337b4ea024f03abc6464c9f35d9718de01cfe6bae9f2e139c397e"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:439c9afe34638ace43a49bf72d201e0ffc1a800295bed8420c2a9ca8d5e3dbb3"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:ba39688799094c75ea8a16a6b544eb57b5b0f3328697084f3f2790892510d144"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:ccd4d5702bb90b84df13bd491be8d900b92016c5a455b7e14630ad7449eb03f8"}, + {file = "pydantic_core-2.14.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:81982d78a45d1e5396819bbb4ece1fadfe5f079335dd28c4ab3427cd95389944"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:7f8210297b04e53bc3da35db08b7302a6a1f4889c79173af69b72ec9754796b8"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:8c8a8812fe6f43a3a5b054af6ac2d7b8605c7bcab2804a8a7d68b53f3cd86e00"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:206ed23aecd67c71daf5c02c3cd19c0501b01ef3cbf7782db9e4e051426b3d0d"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2027d05c8aebe61d898d4cffd774840a9cb82ed356ba47a90d99ad768f39789"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:40180930807ce806aa71eda5a5a5447abb6b6a3c0b4b3b1b1962651906484d68"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:615a0a4bff11c45eb3c1996ceed5bdaa2f7b432425253a7c2eed33bb86d80abc"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f5e412d717366e0677ef767eac93566582518fe8be923361a5c204c1a62eaafe"}, + {file = "pydantic_core-2.14.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:513b07e99c0a267b1d954243845d8a833758a6726a3b5d8948306e3fe14675e3"}, + {file = "pydantic_core-2.14.5.tar.gz", hash = "sha256:6d30226dfc816dd0fdf120cae611dd2215117e4f9b124af8c60ab9093b6e8e71"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pygetwindow" +version = "0.0.9" +description = "A simple, cross-platform module for obtaining GUI information on application's windows." +optional = true +python-versions = "*" +files = [ + {file = "PyGetWindow-0.0.9.tar.gz", hash = "sha256:17894355e7d2b305cd832d717708384017c1698a90ce24f6f7fbf0242dd0a688"}, +] + +[package.dependencies] +pyrect = "*" + [[package]] name = "pygments" version = "2.17.2" @@ -1915,6 +2420,71 @@ files = [ plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] +[[package]] +name = "pymsgbox" +version = "1.0.9" +description = "A simple, cross-platform, pure Python module for JavaScript-like message boxes." +optional = true +python-versions = "*" +files = [ + {file = "PyMsgBox-1.0.9.tar.gz", hash = "sha256:2194227de8bff7a3d6da541848705a155dcbb2a06ee120d9f280a1d7f51263ff"}, +] + +[[package]] +name = "pyobjc-core" +version = "10.1" +description = "Python<->ObjC Interoperability Module" +optional = true +python-versions = ">=3.8" +files = [ + {file = "pyobjc-core-10.1.tar.gz", hash = "sha256:1844f1c8e282839e6fdcb9a9722396c1c12fb1e9331eb68828a26f28a3b2b2b1"}, + {file = "pyobjc_core-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2a72a88222539ad07b5c8be411edc52ff9147d7cef311a2c849869d7bb9603fd"}, + {file = "pyobjc_core-10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fe1b9987b7b0437685fb529832876c2a8463500114960d4e76bb8ae96b6bf208"}, + {file = "pyobjc_core-10.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:9f628779c345d3abd0e20048fb0e256d894c22254577a81a6dcfdb92c3647682"}, + {file = "pyobjc_core-10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25a9e5a2de19238787d24cfa7def6b7fbb94bbe89c0e3109f71c1cb108e8ab44"}, + {file = "pyobjc_core-10.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:2d43205d3a784aa87055b84c0ec0dfa76498e5f18d1ad16bdc58a3dcf5a7d5d0"}, + {file = "pyobjc_core-10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0aa9799b5996a893944999a2f1afcf1de119cab3551c169ad9f54d12e1d38c99"}, +] + +[[package]] +name = "pyobjc-framework-cocoa" +version = "10.1" +description = "Wrappers for the Cocoa frameworks on macOS" +optional = true +python-versions = ">=3.8" +files = [ + {file = "pyobjc-framework-Cocoa-10.1.tar.gz", hash = "sha256:8faaf1292a112e488b777d0c19862d993f3f384f3927dc6eca0d8d2221906a14"}, + {file = "pyobjc_framework_Cocoa-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2e82c2e20b89811d92a7e6e487b6980f360b7c142e2576e90f0e7569caf8202b"}, + {file = "pyobjc_framework_Cocoa-10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0860a9beb7e5c72a1f575679a6d1428a398fa19ad710fb116df899972912e304"}, + {file = "pyobjc_framework_Cocoa-10.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:34b791ea740e1afce211f19334e45469fea9a48d8fce5072e146199fd19ff49f"}, + {file = "pyobjc_framework_Cocoa-10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1398c1a9bebad1a0f2549980e20f4aade00c341b9bac56b4493095a65917d34a"}, + {file = "pyobjc_framework_Cocoa-10.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:22be21226e223d26c9e77645564225787f2b12a750dd17c7ad99c36f428eda14"}, + {file = "pyobjc_framework_Cocoa-10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:0280561f4fb98a864bd23f2c480d907b0edbffe1048654f5dfab160cea8198e6"}, +] + +[package.dependencies] +pyobjc-core = ">=10.1" + +[[package]] +name = "pyobjc-framework-quartz" +version = "10.1" +description = "Wrappers for the Quartz frameworks on macOS" +optional = true +python-versions = ">=3.8" +files = [ + {file = "pyobjc-framework-Quartz-10.1.tar.gz", hash = "sha256:b7439c0a3be9590d261cd2d340ba8dd24a75877b0be3ebce56e022a19cc05738"}, + {file = "pyobjc_framework_Quartz-10.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:69db14ac9814839471e3cf5a8d81fb5edd1b762739ad806d3cf244836dac0154"}, + {file = "pyobjc_framework_Quartz-10.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ddcd18e96511e618ce43e288a043e25524c131f5e6d58775db7aaf15553d849"}, + {file = "pyobjc_framework_Quartz-10.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c4257a2fb5580e5ebe927a66cf36a11749685a4681a30f90e954a3f08894cb62"}, + {file = "pyobjc_framework_Quartz-10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:28315ca6e04a08ae9e4eaf35b364ee77e081605d5865021018217626097c5e80"}, + {file = "pyobjc_framework_Quartz-10.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:9cb859a2fd7e15f2de85c16b028148dea06002d1a4142922b3441d3802fab372"}, + {file = "pyobjc_framework_Quartz-10.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:993c71009e6374e57205e6aeaa577b7af2df245a5d1d2feff0f88ca0fa7b8626"}, +] + +[package.dependencies] +pyobjc-core = ">=10.1" +pyobjc-framework-Cocoa = ">=10.1" + [[package]] name = "pyparsing" version = "3.1.1" @@ -1929,6 +2499,16 @@ files = [ [package.extras] diagrams = ["jinja2", "railroad-diagrams"] +[[package]] +name = "pyperclip" +version = "1.8.2" +description = "A cross-platform clipboard module for Python. (Only handles plain text for now.)" +optional = true +python-versions = "*" +files = [ + {file = "pyperclip-1.8.2.tar.gz", hash = "sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57"}, +] + [[package]] name = "pyreadline3" version = "3.4.1" @@ -1940,6 +2520,47 @@ files = [ {file = "pyreadline3-3.4.1.tar.gz", hash = "sha256:6f3d1f7b8a31ba32b73917cefc1f28cc660562f39aea8646d30bd6eff21f7bae"}, ] +[[package]] +name = "pyrect" +version = "0.2.0" +description = "PyRect is a simple module with a Rect class for Pygame-like rectangular areas." +optional = true +python-versions = "*" +files = [ + {file = "PyRect-0.2.0.tar.gz", hash = "sha256:f65155f6df9b929b67caffbd57c0947c5ae5449d3b580d178074bffb47a09b78"}, +] + +[[package]] +name = "pyscreeze" +version = "0.1.30" +description = "A simple, cross-platform screenshot module for Python 2 and 3." +optional = true +python-versions = "*" +files = [ + {file = "PyScreeze-0.1.30.tar.gz", hash = "sha256:74098ad048e76a6231dcfa6243343af94459b8c829f9ccb7a44a5d3b147a67d1"}, +] + +[package.dependencies] +Pillow = [ + {version = ">=9.3.0", markers = "python_version == \"3.11\""}, + {version = ">=9.2.0", markers = "python_version == \"3.10\""}, +] + +[[package]] +name = "pytesseract" +version = "0.3.10" +description = "Python-tesseract is a python wrapper for Google's Tesseract-OCR" +optional = true +python-versions = ">=3.7" +files = [ + {file = "pytesseract-0.3.10-py3-none-any.whl", hash = "sha256:8f22cc98f765bf13517ead0c70effedb46c153540d25783e04014f28b55a5fc6"}, + {file = "pytesseract-0.3.10.tar.gz", hash = "sha256:f1c3a8b0f07fd01a1085d451f5b8315be6eec1d5577a6796d46dc7a62bd4120f"}, +] + +[package.dependencies] +packaging = ">=21.3" +Pillow = ">=8.0.0" + [[package]] name = "pytest" version = "7.4.3" @@ -2002,6 +2623,26 @@ files = [ {file = "python_editor-1.0.4-py3-none-any.whl", hash = "sha256:1bf6e860a8ad52a14c3ee1252d5dc25b2030618ed80c022598f00176adc8367d"}, ] +[[package]] +name = "python3-xlib" +version = "0.15" +description = "Python3 X Library" +optional = true +python-versions = "*" +files = [ + {file = "python3-xlib-0.15.tar.gz", hash = "sha256:dc4245f3ae4aa5949c1d112ee4723901ade37a96721ba9645f2bfa56e5b383f8"}, +] + +[[package]] +name = "pytweening" +version = "1.0.7" +description = "A collection of tweening / easing functions." +optional = true +python-versions = "*" +files = [ + {file = "pytweening-1.0.7.tar.gz", hash = "sha256:767134f1bf57b76c1ce9f692dd1cfc776d9a279de6724e8d04854508fd7ededb"}, +] + [[package]] name = "pywin32" version = "306" @@ -2203,6 +2844,21 @@ files = [ [package.dependencies] setuptools = ">=41.0" +[[package]] +name = "referencing" +version = "0.32.0" +description = "JSON Referencing + Python" +optional = true +python-versions = ">=3.8" +files = [ + {file = "referencing-0.32.0-py3-none-any.whl", hash = "sha256:bdcd3efb936f82ff86f993093f6da7435c7de69a3b3a5a06678a6050184bee99"}, + {file = "referencing-0.32.0.tar.gz", hash = "sha256:689e64fe121843dcfd57b71933318ef1f91188ffb45367332700a86ac8fd6161"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + [[package]] name = "regex" version = "2023.10.3" @@ -2321,6 +2977,33 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "requirementslib" +version = "3.0.0" +description = "A tool for converting between pip-style and pipfile requirements." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requirementslib-3.0.0-py2.py3-none-any.whl", hash = "sha256:67b42903d7c32f89c7047d1020c619d37cb515c475a4ae6f4e5683e1c56d7bf7"}, + {file = "requirementslib-3.0.0.tar.gz", hash = "sha256:28f8e0b1c38b34ae06de68ef115b03bbcdcdb99f9e9393333ff06ded443e3f24"}, +] + +[package.dependencies] +distlib = ">=0.2.8" +pep517 = ">=0.5.0" +pip = ">=23.1" +platformdirs = "*" +plette = {version = "*", extras = ["validation"]} +pydantic = "*" +requests = "*" +setuptools = ">=40.8" +tomlkit = ">=0.5.3" + +[package.extras] +dev = ["nox", "parver", "towncrier", "twine"] +docs = ["sphinx", "sphinx-rtd-theme"] +tests = ["coverage", "hypothesis", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "readme-renderer[md]"] + [[package]] name = "rich" version = "13.7.0" @@ -2339,6 +3022,242 @@ pygments = ">=2.13.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] +[[package]] +name = "rpds-py" +version = "0.13.2" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = true +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.13.2-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:1ceebd0ae4f3e9b2b6b553b51971921853ae4eebf3f54086be0565d59291e53d"}, + {file = "rpds_py-0.13.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:46e1ed994a0920f350a4547a38471217eb86f57377e9314fbaaa329b71b7dfe3"}, + {file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee353bb51f648924926ed05e0122b6a0b1ae709396a80eb583449d5d477fcdf7"}, + {file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:530190eb0cd778363bbb7596612ded0bb9fef662daa98e9d92a0419ab27ae914"}, + {file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29d311e44dd16d2434d5506d57ef4d7036544fc3c25c14b6992ef41f541b10fb"}, + {file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2e72f750048b32d39e87fc85c225c50b2a6715034848dbb196bf3348aa761fa1"}, + {file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db09b98c7540df69d4b47218da3fbd7cb466db0fb932e971c321f1c76f155266"}, + {file = "rpds_py-0.13.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2ac26f50736324beb0282c819668328d53fc38543fa61eeea2c32ea8ea6eab8d"}, + {file = "rpds_py-0.13.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:12ecf89bd54734c3c2c79898ae2021dca42750c7bcfb67f8fb3315453738ac8f"}, + {file = "rpds_py-0.13.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a44c8440183b43167fd1a0819e8356692bf5db1ad14ce140dbd40a1485f2dea"}, + {file = "rpds_py-0.13.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bcef4f2d3dc603150421de85c916da19471f24d838c3c62a4f04c1eb511642c1"}, + {file = "rpds_py-0.13.2-cp310-none-win32.whl", hash = "sha256:ee6faebb265e28920a6f23a7d4c362414b3f4bb30607141d718b991669e49ddc"}, + {file = "rpds_py-0.13.2-cp310-none-win_amd64.whl", hash = "sha256:ac96d67b37f28e4b6ecf507c3405f52a40658c0a806dffde624a8fcb0314d5fd"}, + {file = "rpds_py-0.13.2-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:b5f6328e8e2ae8238fc767703ab7b95785521c42bb2b8790984e3477d7fa71ad"}, + {file = "rpds_py-0.13.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:729408136ef8d45a28ee9a7411917c9e3459cf266c7e23c2f7d4bb8ef9e0da42"}, + {file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65cfed9c807c27dee76407e8bb29e6f4e391e436774bcc769a037ff25ad8646e"}, + {file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aefbdc934115d2f9278f153952003ac52cd2650e7313750390b334518c589568"}, + {file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d48db29bd47814671afdd76c7652aefacc25cf96aad6daefa82d738ee87461e2"}, + {file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3c55d7f2d817183d43220738270efd3ce4e7a7b7cbdaefa6d551ed3d6ed89190"}, + {file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6aadae3042f8e6db3376d9e91f194c606c9a45273c170621d46128f35aef7cd0"}, + {file = "rpds_py-0.13.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5feae2f9aa7270e2c071f488fab256d768e88e01b958f123a690f1cc3061a09c"}, + {file = "rpds_py-0.13.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:51967a67ea0d7b9b5cd86036878e2d82c0b6183616961c26d825b8c994d4f2c8"}, + {file = "rpds_py-0.13.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d0c10d803549427f427085ed7aebc39832f6e818a011dcd8785e9c6a1ba9b3e"}, + {file = "rpds_py-0.13.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:603d5868f7419081d616dab7ac3cfa285296735e7350f7b1e4f548f6f953ee7d"}, + {file = "rpds_py-0.13.2-cp311-none-win32.whl", hash = "sha256:b8996ffb60c69f677245f5abdbcc623e9442bcc91ed81b6cd6187129ad1fa3e7"}, + {file = "rpds_py-0.13.2-cp311-none-win_amd64.whl", hash = "sha256:5379e49d7e80dca9811b36894493d1c1ecb4c57de05c36f5d0dd09982af20211"}, + {file = "rpds_py-0.13.2-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:8a776a29b77fe0cc28fedfd87277b0d0f7aa930174b7e504d764e0b43a05f381"}, + {file = "rpds_py-0.13.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2a1472956c5bcc49fb0252b965239bffe801acc9394f8b7c1014ae9258e4572b"}, + {file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f252dfb4852a527987a9156cbcae3022a30f86c9d26f4f17b8c967d7580d65d2"}, + {file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f0d320e70b6b2300ff6029e234e79fe44e9dbbfc7b98597ba28e054bd6606a57"}, + {file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ade2ccb937060c299ab0dfb2dea3d2ddf7e098ed63ee3d651ebfc2c8d1e8632a"}, + {file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9d121be0217787a7d59a5c6195b0842d3f701007333426e5154bf72346aa658"}, + {file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fa6bd071ec6d90f6e7baa66ae25820d57a8ab1b0a3c6d3edf1834d4b26fafa2"}, + {file = "rpds_py-0.13.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c918621ee0a3d1fe61c313f2489464f2ae3d13633e60f520a8002a5e910982ee"}, + {file = "rpds_py-0.13.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:25b28b3d33ec0a78e944aaaed7e5e2a94ac811bcd68b557ca48a0c30f87497d2"}, + {file = "rpds_py-0.13.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:31e220a040b89a01505128c2f8a59ee74732f666439a03e65ccbf3824cdddae7"}, + {file = "rpds_py-0.13.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:15253fff410873ebf3cfba1cc686a37711efcd9b8cb30ea21bb14a973e393f60"}, + {file = "rpds_py-0.13.2-cp312-none-win32.whl", hash = "sha256:b981a370f8f41c4024c170b42fbe9e691ae2dbc19d1d99151a69e2c84a0d194d"}, + {file = "rpds_py-0.13.2-cp312-none-win_amd64.whl", hash = "sha256:4c4e314d36d4f31236a545696a480aa04ea170a0b021e9a59ab1ed94d4c3ef27"}, + {file = "rpds_py-0.13.2-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:80e5acb81cb49fd9f2d5c08f8b74ffff14ee73b10ca88297ab4619e946bcb1e1"}, + {file = "rpds_py-0.13.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:efe093acc43e869348f6f2224df7f452eab63a2c60a6c6cd6b50fd35c4e075ba"}, + {file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c2a61c0e4811012b0ba9f6cdcb4437865df5d29eab5d6018ba13cee1c3064a0"}, + {file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:751758d9dd04d548ec679224cc00e3591f5ebf1ff159ed0d4aba6a0746352452"}, + {file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6ba8858933f0c1a979781272a5f65646fca8c18c93c99c6ddb5513ad96fa54b1"}, + {file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfdfbe6a36bc3059fff845d64c42f2644cf875c65f5005db54f90cdfdf1df815"}, + {file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa0379c1935c44053c98826bc99ac95f3a5355675a297ac9ce0dfad0ce2d50ca"}, + {file = "rpds_py-0.13.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d5593855b5b2b73dd8413c3fdfa5d95b99d657658f947ba2c4318591e745d083"}, + {file = "rpds_py-0.13.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:2a7bef6977043673750a88da064fd513f89505111014b4e00fbdd13329cd4e9a"}, + {file = "rpds_py-0.13.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:3ab96754d23372009638a402a1ed12a27711598dd49d8316a22597141962fe66"}, + {file = "rpds_py-0.13.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:e06cfea0ece444571d24c18ed465bc93afb8c8d8d74422eb7026662f3d3f779b"}, + {file = "rpds_py-0.13.2-cp38-none-win32.whl", hash = "sha256:5493569f861fb7b05af6d048d00d773c6162415ae521b7010197c98810a14cab"}, + {file = "rpds_py-0.13.2-cp38-none-win_amd64.whl", hash = "sha256:b07501b720cf060c5856f7b5626e75b8e353b5f98b9b354a21eb4bfa47e421b1"}, + {file = "rpds_py-0.13.2-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:881df98f0a8404d32b6de0fd33e91c1b90ed1516a80d4d6dc69d414b8850474c"}, + {file = "rpds_py-0.13.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d79c159adea0f1f4617f54aa156568ac69968f9ef4d1e5fefffc0a180830308e"}, + {file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38d4f822ee2f338febcc85aaa2547eb5ba31ba6ff68d10b8ec988929d23bb6b4"}, + {file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5d75d6d220d55cdced2f32cc22f599475dbe881229aeddba6c79c2e9df35a2b3"}, + {file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5d97e9ae94fb96df1ee3cb09ca376c34e8a122f36927230f4c8a97f469994bff"}, + {file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67a429520e97621a763cf9b3ba27574779c4e96e49a27ff8a1aa99ee70beb28a"}, + {file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:188435794405c7f0573311747c85a96b63c954a5f2111b1df8018979eca0f2f0"}, + {file = "rpds_py-0.13.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:38f9bf2ad754b4a45b8210a6c732fe876b8a14e14d5992a8c4b7c1ef78740f53"}, + {file = "rpds_py-0.13.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6ba2cb7d676e9415b9e9ac7e2aae401dc1b1e666943d1f7bc66223d3d73467b"}, + {file = "rpds_py-0.13.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:eaffbd8814bb1b5dc3ea156a4c5928081ba50419f9175f4fc95269e040eff8f0"}, + {file = "rpds_py-0.13.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a4c1058cdae6237d97af272b326e5f78ee7ee3bbffa6b24b09db4d828810468"}, + {file = "rpds_py-0.13.2-cp39-none-win32.whl", hash = "sha256:b5267feb19070bef34b8dea27e2b504ebd9d31748e3ecacb3a4101da6fcb255c"}, + {file = "rpds_py-0.13.2-cp39-none-win_amd64.whl", hash = "sha256:ddf23960cb42b69bce13045d5bc66f18c7d53774c66c13f24cf1b9c144ba3141"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:97163a1ab265a1073a6372eca9f4eeb9f8c6327457a0b22ddfc4a17dcd613e74"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:25ea41635d22b2eb6326f58e608550e55d01df51b8a580ea7e75396bafbb28e9"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d59d4d451ba77f08cb4cd9268dec07be5bc65f73666302dbb5061989b17198"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7c564c58cf8f248fe859a4f0fe501b050663f3d7fbc342172f259124fb59933"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61dbc1e01dc0c5875da2f7ae36d6e918dc1b8d2ce04e871793976594aad8a57a"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fdb82eb60d31b0c033a8e8ee9f3fc7dfbaa042211131c29da29aea8531b4f18f"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d204957169f0b3511fb95395a9da7d4490fb361763a9f8b32b345a7fe119cb45"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c45008ca79bad237cbc03c72bc5205e8c6f66403773929b1b50f7d84ef9e4d07"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:79bf58c08f0756adba691d480b5a20e4ad23f33e1ae121584cf3a21717c36dfa"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e86593bf8637659e6a6ed58854b6c87ec4e9e45ee8a4adfd936831cef55c2d21"}, + {file = "rpds_py-0.13.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:d329896c40d9e1e5c7715c98529e4a188a1f2df51212fd65102b32465612b5dc"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:4a5375c5fff13f209527cd886dc75394f040c7d1ecad0a2cb0627f13ebe78a12"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:06d218e4464d31301e943b65b2c6919318ea6f69703a351961e1baaf60347276"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1f41d32a2ddc5a94df4b829b395916a4b7f103350fa76ba6de625fcb9e773ac"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6bc568b05e02cd612be53900c88aaa55012e744930ba2eeb56279db4c6676eb3"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d94d78418203904730585efa71002286ac4c8ac0689d0eb61e3c465f9e608ff"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bed0252c85e21cf73d2d033643c945b460d6a02fc4a7d644e3b2d6f5f2956c64"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:244e173bb6d8f3b2f0c4d7370a1aa341f35da3e57ffd1798e5b2917b91731fd3"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7f55cd9cf1564b7b03f238e4c017ca4794c05b01a783e9291065cb2858d86ce4"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:f03a1b3a4c03e3e0161642ac5367f08479ab29972ea0ffcd4fa18f729cd2be0a"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:f5f4424cb87a20b016bfdc157ff48757b89d2cc426256961643d443c6c277007"}, + {file = "rpds_py-0.13.2-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:c82bbf7e03748417c3a88c1b0b291288ce3e4887a795a3addaa7a1cfd9e7153e"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:c0095b8aa3e432e32d372e9a7737e65b58d5ed23b9620fea7cb81f17672f1fa1"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:4c2d26aa03d877c9730bf005621c92da263523a1e99247590abbbe252ccb7824"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96f2975fb14f39c5fe75203f33dd3010fe37d1c4e33177feef1107b5ced750e3"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4dcc5ee1d0275cb78d443fdebd0241e58772a354a6d518b1d7af1580bbd2c4e8"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61d42d2b08430854485135504f672c14d4fc644dd243a9c17e7c4e0faf5ed07e"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d3a61e928feddc458a55110f42f626a2a20bea942ccedb6fb4cee70b4830ed41"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7de12b69d95072394998c622cfd7e8cea8f560db5fca6a62a148f902a1029f8b"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:87a90f5545fd61f6964e65eebde4dc3fa8660bb7d87adb01d4cf17e0a2b484ad"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:9c95a1a290f9acf7a8f2ebbdd183e99215d491beea52d61aa2a7a7d2c618ddc6"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:35f53c76a712e323c779ca39b9a81b13f219a8e3bc15f106ed1e1462d56fcfe9"}, + {file = "rpds_py-0.13.2-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:96fb0899bb2ab353f42e5374c8f0789f54e0a94ef2f02b9ac7149c56622eaf31"}, + {file = "rpds_py-0.13.2.tar.gz", hash = "sha256:f8eae66a1304de7368932b42d801c67969fd090ddb1a7a24f27b435ed4bed68f"}, +] + +[[package]] +name = "ruamel-yaml" +version = "0.17.40" +description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" +optional = true +python-versions = ">=3" +files = [ + {file = "ruamel.yaml-0.17.40-py3-none-any.whl", hash = "sha256:b16b6c3816dff0a93dca12acf5e70afd089fa5acb80604afd1ffa8b465b7722c"}, + {file = "ruamel.yaml-0.17.40.tar.gz", hash = "sha256:6024b986f06765d482b5b07e086cc4b4cd05dd22ddcbc758fa23d54873cf313d"}, +] + +[package.dependencies] +"ruamel.yaml.clib" = {version = ">=0.2.7", markers = "platform_python_implementation == \"CPython\" and python_version < \"3.13\""} + +[package.extras] +docs = ["mercurial (>5.7)", "ryd"] +jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"] + +[[package]] +name = "ruamel-yaml-clib" +version = "0.2.8" +description = "C version of reader, parser and emitter for ruamel.yaml derived from libyaml" +optional = true +python-versions = ">=3.6" +files = [ + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b42169467c42b692c19cf539c38d4602069d8c1505e97b86387fcf7afb766e1d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-macosx_13_0_arm64.whl", hash = "sha256:07238db9cbdf8fc1e9de2489a4f68474e70dffcb32232db7c08fa61ca0c7c462"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fff3573c2db359f091e1589c3d7c5fc2f86f5bdb6f24252c2d8e539d4e45f412"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-manylinux_2_24_aarch64.whl", hash = "sha256:aa2267c6a303eb483de8d02db2871afb5c5fc15618d894300b88958f729ad74f"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:840f0c7f194986a63d2c2465ca63af8ccbbc90ab1c6001b1978f05119b5e7334"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:024cfe1fc7c7f4e1aff4a81e718109e13409767e4f871443cbff3dba3578203d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win32.whl", hash = "sha256:c69212f63169ec1cfc9bb44723bf2917cbbd8f6191a00ef3410f5a7fe300722d"}, + {file = "ruamel.yaml.clib-0.2.8-cp310-cp310-win_amd64.whl", hash = "sha256:cabddb8d8ead485e255fe80429f833172b4cadf99274db39abc080e068cbcc31"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:bef08cd86169d9eafb3ccb0a39edb11d8e25f3dae2b28f5c52fd997521133069"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-macosx_13_0_arm64.whl", hash = "sha256:b16420e621d26fdfa949a8b4b47ade8810c56002f5389970db4ddda51dbff248"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:25c515e350e5b739842fc3228d662413ef28f295791af5e5110b543cf0b57d9b"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-manylinux_2_24_aarch64.whl", hash = "sha256:1707814f0d9791df063f8c19bb51b0d1278b8e9a2353abbb676c2f685dee6afe"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:46d378daaac94f454b3a0e3d8d78cafd78a026b1d71443f4966c696b48a6d899"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:09b055c05697b38ecacb7ac50bdab2240bfca1a0c4872b0fd309bb07dc9aa3a9"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win32.whl", hash = "sha256:53a300ed9cea38cf5a2a9b069058137c2ca1ce658a874b79baceb8f892f915a7"}, + {file = "ruamel.yaml.clib-0.2.8-cp311-cp311-win_amd64.whl", hash = "sha256:c2a72e9109ea74e511e29032f3b670835f8a59bbdc9ce692c5b4ed91ccf1eedb"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:ebc06178e8821efc9692ea7544aa5644217358490145629914d8020042c24aa1"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-macosx_13_0_arm64.whl", hash = "sha256:edaef1c1200c4b4cb914583150dcaa3bc30e592e907c01117c08b13a07255ec2"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d176b57452ab5b7028ac47e7b3cf644bcfdc8cacfecf7e71759f7f51a59e5c92"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-manylinux_2_24_aarch64.whl", hash = "sha256:1dc67314e7e1086c9fdf2680b7b6c2be1c0d8e3a8279f2e993ca2a7545fecf62"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:3213ece08ea033eb159ac52ae052a4899b56ecc124bb80020d9bbceeb50258e9"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aab7fd643f71d7946f2ee58cc88c9b7bfc97debd71dcc93e03e2d174628e7e2d"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win32.whl", hash = "sha256:5c365d91c88390c8d0a8545df0b5857172824b1c604e867161e6b3d59a827eaa"}, + {file = "ruamel.yaml.clib-0.2.8-cp312-cp312-win_amd64.whl", hash = "sha256:1758ce7d8e1a29d23de54a16ae867abd370f01b5a69e1a3ba75223eaa3ca1a1b"}, + {file = "ruamel.yaml.clib-0.2.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a5aa27bad2bb83670b71683aae140a1f52b0857a2deff56ad3f6c13a017a26ed"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c58ecd827313af6864893e7af0a3bb85fd529f862b6adbefe14643947cfe2942"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-macosx_12_0_arm64.whl", hash = "sha256:f481f16baec5290e45aebdc2a5168ebc6d35189ae6fea7a58787613a25f6e875"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_24_aarch64.whl", hash = "sha256:77159f5d5b5c14f7c34073862a6b7d34944075d9f93e681638f6d753606c6ce6"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7f67a1ee819dc4562d444bbafb135832b0b909f81cc90f7aa00260968c9ca1b3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4ecbf9c3e19f9562c7fdd462e8d18dd902a47ca046a2e64dba80699f0b6c09b7"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:87ea5ff66d8064301a154b3933ae406b0863402a799b16e4a1d24d9fbbcbe0d3"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win32.whl", hash = "sha256:75e1ed13e1f9de23c5607fe6bd1aeaae21e523b32d83bb33918245361e9cc51b"}, + {file = "ruamel.yaml.clib-0.2.8-cp37-cp37m-win_amd64.whl", hash = "sha256:3f215c5daf6a9d7bbed4a0a4f760f3113b10e82ff4c5c44bec20a68c8014f675"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1b617618914cb00bf5c34d4357c37aa15183fa229b24767259657746c9077615"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-macosx_12_0_arm64.whl", hash = "sha256:a6a9ffd280b71ad062eae53ac1659ad86a17f59a0fdc7699fd9be40525153337"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_24_aarch64.whl", hash = "sha256:305889baa4043a09e5b76f8e2a51d4ffba44259f6b4c72dec8ca56207d9c6fe1"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:700e4ebb569e59e16a976857c8798aee258dceac7c7d6b50cab63e080058df91"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:e2b4c44b60eadec492926a7270abb100ef9f72798e18743939bdbf037aab8c28"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e79e5db08739731b0ce4850bed599235d601701d5694c36570a99a0c5ca41a9d"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win32.whl", hash = "sha256:955eae71ac26c1ab35924203fda6220f84dce57d6d7884f189743e2abe3a9fbe"}, + {file = "ruamel.yaml.clib-0.2.8-cp38-cp38-win_amd64.whl", hash = "sha256:56f4252222c067b4ce51ae12cbac231bce32aee1d33fbfc9d17e5b8d6966c312"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:03d1162b6d1df1caa3a4bd27aa51ce17c9afc2046c31b0ad60a0a96ec22f8001"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:bba64af9fa9cebe325a62fa398760f5c7206b215201b0ec825005f1b18b9bccf"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_24_aarch64.whl", hash = "sha256:a1a45e0bb052edf6a1d3a93baef85319733a888363938e1fc9924cb00c8df24c"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:da09ad1c359a728e112d60116f626cc9f29730ff3e0e7db72b9a2dbc2e4beed5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:184565012b60405d93838167f425713180b949e9d8dd0bbc7b49f074407c5a8b"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a75879bacf2c987c003368cf14bed0ffe99e8e85acfa6c0bfffc21a090f16880"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win32.whl", hash = "sha256:84b554931e932c46f94ab306913ad7e11bba988104c5cff26d90d03f68258cd5"}, + {file = "ruamel.yaml.clib-0.2.8-cp39-cp39-win_amd64.whl", hash = "sha256:25ac8c08322002b06fa1d49d1646181f0b2c72f5cbc15a85e80b4c30a544bb15"}, + {file = "ruamel.yaml.clib-0.2.8.tar.gz", hash = "sha256:beb2e0404003de9a4cab9753a8805a8fe9320ee6673136ed7f04255fe60bb512"}, +] + +[[package]] +name = "rubicon-objc" +version = "0.4.7" +description = "A bridge between an Objective C runtime environment and Python." +optional = true +python-versions = ">=3.8" +files = [ + {file = "rubicon-objc-0.4.7.tar.gz", hash = "sha256:be937d864bd1229f860defabb89b40c53634eedc36448d89ad3c14eb3286e509"}, + {file = "rubicon_objc-0.4.7-py3-none-any.whl", hash = "sha256:f37108e35d5da1a78ab3eed2d03b095934f5f618329a939e4bd2ada9894eff6e"}, +] + +[package.extras] +dev = ["pre-commit (==3.5.0)", "pytest (==7.4.2)", "pytest-tldr (==0.2.5)", "setuptools-scm[toml] (==8.0.4)", "tox (==4.11.3)"] +docs = ["furo (==2023.9.10)", "pyenchant (==3.2.2)", "sphinx (==7.1.2)", "sphinx (==7.2.6)", "sphinx-autobuild (==2021.3.14)", "sphinx-copybutton (==0.5.2)", "sphinx-tabs (==3.4.1)", "sphinxcontrib-spelling (==8.0.0)"] + +[[package]] +name = "semgrep" +version = "1.52.0" +description = "Lightweight static analysis for many languages. Find bug variants with patterns that look like source code." +optional = true +python-versions = ">=3.8" +files = [ + {file = "semgrep-1.52.0-cp38.cp39.cp310.cp311.py37.py38.py39.py310.py311-none-any.whl", hash = "sha256:c6f342cfeddfb0655ed40e1776b73cbb7df9f47964b79de0399cf67a596e0ece"}, + {file = "semgrep-1.52.0-cp38.cp39.cp310.cp311.py37.py38.py39.py310.py311-none-macosx_10_14_x86_64.whl", hash = "sha256:1bf77f060dfac5c9a2585c2d9c0f6ce46bdf0fe5c06b8aacd1a4facdf530341e"}, + {file = "semgrep-1.52.0-cp38.cp39.cp310.cp311.py37.py38.py39.py310.py311-none-macosx_11_0_arm64.whl", hash = "sha256:5cbfc762d993cc37eed3a4b322e46f1217ee4c03d6bb5cbeee1172c46921b2d9"}, + {file = "semgrep-1.52.0-cp38.cp39.cp310.cp311.py37.py38.py39.py310.py311-none-musllinux_1_0_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22fa2544fa4b4e65527cfca35b891302c7a106929deb165f44882d5b0b731f76"}, + {file = "semgrep-1.52.0.tar.gz", hash = "sha256:e05c03ce184898a43dde491b4f5000a551d730127c40727947e649817ea5ea97"}, +] + +[package.dependencies] +attrs = ">=21.3" +boltons = ">=21.0,<22.0" +click = ">=8.1,<9.0" +click-option-group = ">=0.5,<1.0" +colorama = ">=0.4.0,<0.5.0" +defusedxml = ">=0.7.1,<0.8.0" +glom = ">=22.1,<23.0" +jsonschema = ">=4.6,<5.0" +packaging = ">=21.0" +peewee = ">=3.14,<4.0" +requests = ">=2.22,<3.0" +rich = ">=12.6.0" +"ruamel.yaml" = ">=0.16.0,<0.18" +tomli = ">=2.0.1,<2.1.0" +typing-extensions = ">=4.2,<5.0" +urllib3 = ">=1.26,<2.0" +wcmatch = ">=8.3,<9.0" + +[package.extras] +experiments = ["jsonnet (>=0.18,<1.0)"] + [[package]] name = "setuptools" version = "69.0.2" @@ -2411,7 +3330,7 @@ tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] name = "termcolor" version = "2.4.0" description = "ANSI color formatting for output in terminal" -optional = false +optional = true python-versions = ">=3.8" files = [ {file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"}, @@ -2466,6 +3385,24 @@ requests = ">=2.26.0" [package.extras] blobfile = ["blobfile (>=2)"] +[[package]] +name = "tinycss2" +version = "1.2.1" +description = "A tiny CSS parser" +optional = true +python-versions = ">=3.7" +files = [ + {file = "tinycss2-1.2.1-py3-none-any.whl", hash = "sha256:2b80a96d41e7c3914b8cda8bc7f705a4d9c49275616e886103dd839dfc847847"}, + {file = "tinycss2-1.2.1.tar.gz", hash = "sha256:8cff3a8f066c2ec677c06dbc7b45619804a6938478d9d73c284b29d14ecb0627"}, +] + +[package.dependencies] +webencodings = ">=0.4" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + [[package]] name = "tokenizers" version = "0.15.0" @@ -2606,6 +3543,17 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "tomlkit" +version = "0.12.3" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.12.3-py3-none-any.whl", hash = "sha256:b0a645a9156dc7cb5d3a1f0d4bab66db287fcb8e0430bdd4664a095ea16414ba"}, + {file = "tomlkit-0.12.3.tar.gz", hash = "sha256:75baf5012d06501f07bee5bf8e801b9f343e7aac5a92581f20f80ce632e6b5a4"}, +] + [[package]] name = "tornado" version = "6.4" @@ -2663,30 +3611,30 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "typing-extensions" -version = "4.8.0" +version = "4.9.0" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.8.0-py3-none-any.whl", hash = "sha256:8f92fc8806f9a6b641eaa5318da32b44d401efaac0f6678c9bc448ba3605faa0"}, - {file = "typing_extensions-4.8.0.tar.gz", hash = "sha256:df8e4339e9cb77357558cbdbceca33c303714cf861d1eef15e1070055ae8b7ef"}, + {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, + {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, ] [[package]] name = "urllib3" -version = "2.1.0" +version = "1.26.18" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-1.26.18-py2.py3-none-any.whl", hash = "sha256:34b97092d7e0a3a8cf7cd10e386f401b3737364026c45e622aa02903dffe0f07"}, + {file = "urllib3-1.26.18.tar.gz", hash = "sha256:f8ecc1bba5667413457c529ab955bf8c67b45db799d159066261719e328580a0"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] -zstd = ["zstandard (>=0.18.0)"] +brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "virtualenv" @@ -2708,6 +3656,20 @@ platformdirs = ">=3.9.1,<5" docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +[[package]] +name = "wcmatch" +version = "8.5" +description = "Wildcard/glob file name matcher." +optional = true +python-versions = ">=3.8" +files = [ + {file = "wcmatch-8.5-py3-none-any.whl", hash = "sha256:14554e409b142edeefab901dc68ad570b30a72a8ab9a79106c5d5e9a6d241bd5"}, + {file = "wcmatch-8.5.tar.gz", hash = "sha256:86c17572d0f75cbf3bcb1a18f3bf2f9e72b39a9c08c9b4a74e991e1882a8efb3"}, +] + +[package.dependencies] +bracex = ">=2.1.1" + [[package]] name = "wcwidth" version = "0.2.12" @@ -2719,6 +3681,17 @@ files = [ {file = "wcwidth-0.2.12.tar.gz", hash = "sha256:f01c104efdf57971bcb756f054dd58ddec5204dd15fa31d6503ea57947d97c02"}, ] +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = true +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + [[package]] name = "websocket-client" version = "1.7.0" @@ -2745,6 +3718,20 @@ files = [ {file = "wget-3.2.zip", hash = "sha256:35e630eca2aa50ce998b9b1a127bb26b30dfee573702782aa982f875e3f16061"}, ] +[[package]] +name = "yarg" +version = "0.1.9" +description = "A semi hard Cornish cheese, also queries PyPI (PyPI client)" +optional = false +python-versions = "*" +files = [ + {file = "yarg-0.1.9-py2.py3-none-any.whl", hash = "sha256:4f9cebdc00fac946c9bf2783d634e538a71c7d280a4d806d45fd4dc0ef441492"}, + {file = "yarg-0.1.9.tar.gz", hash = "sha256:55695bf4d1e3e7f756496c36a69ba32c40d18f821e38f61d028f6049e5e15911"}, +] + +[package.dependencies] +requests = "*" + [[package]] name = "yarl" version = "1.9.4" @@ -2852,7 +3839,7 @@ multidict = ">=4.0" name = "yaspin" version = "3.0.1" description = "Yet Another Terminal Spinner" -optional = false +optional = true python-versions = ">=3.9,<4.0" files = [ {file = "yaspin-3.0.1-py3-none-any.whl", hash = "sha256:c4b5d2ca23ae664b87a5cd53401c5107cef12668a71d9ee5ea5536045f364121"}, @@ -2878,9 +3865,10 @@ docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.link testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] [extras] -safe = [] +os = ["ipython", "matplotlib", "opencv-python", "pyautogui", "pytesseract"] +safe = ["semgrep"] [metadata] lock-version = "2.0" python-versions = ">=3.10,<3.12" -content-hash = "ee6c0176f94e57258c0629de930f15f245c74d0bea0666f78280a464641839b8" +content-hash = "5110a472208cecf386bde54d1ae2b6c73cd2f23e5e06e1fc2830a507be70d88c" diff --git a/pyproject.toml b/pyproject.toml index 9986c97bf4..d4422664b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,6 @@ six = "^1.16.0" tiktoken = "^0.4.0" tokentrim = "^0.1.13" wget = "^3.2" -yaspin = "^3.0.1" psutil = "^5.9.6" pyreadline3 = {version = "^3.4.1", markers = "sys_platform == 'win32'"} html2image = "^2.0.4.3" @@ -31,6 +30,19 @@ ipykernel = "^6.26.0" jupyter-client = "^8.6.0" matplotlib = "^3.8.2" +#Optional dependencies +pytesseract = { version = "^0.3.10", optional = true } +pyautogui = { version = "^0.9.54", optional = true } +opencv-python = { version = "^4.8.1.78", optional = true } +ipython = { version = "^8.18.1", optional = true } +cairosvg = { version = "^2.7.1", optional = true } +semgrep = { version = "^1.52.0", optional = true } +yaspin = { version = "^3.0.1", optional = true } + +[tool.poetry.extras] +os = ["matplotlib", "pytesseract", "pyautogui", "opencv-python", "ipython"] +safe = ["semgrep"] + [tool.poetry.group.dev.dependencies] black = "^23.10.1" isort = "^5.12.0" @@ -45,9 +57,6 @@ build-backend = "poetry.core.masonry.api" [tool.poetry.scripts] interpreter = "interpreter:start_terminal_interface" -[tool.poetry.extras] -safe = ["semgrep"] - [tool.black] target-version = ['py311'] diff --git a/tests/test_interpreter.py b/tests/test_interpreter.py index 32538dc1a9..5e52ed8ce8 100644 --- a/tests/test_interpreter.py +++ b/tests/test_interpreter.py @@ -1,4 +1,5 @@ import os +import platform import time from random import randint @@ -27,6 +28,11 @@ def teardown_function(): time.sleep(4) +@pytest.mark.skip(reason="Mac only + no way to fail test") +def test_spotlight(): + interpreter.computer.keyboard.hotkey("command", "space") + + def test_config_loading(): # because our test is running from the root directory, we need to do some # path manipulation to get the actual path to the config file or our config