From c0132237f0bef6aa61a548df1b56afa03f814ac4 Mon Sep 17 00:00:00 2001 From: Vadym Parakonnyi Date: Sun, 21 Jul 2024 15:35:51 +0200 Subject: [PATCH] feat: fix e2e test with pytest-playwright, use ruff, use pre-commit, --- .github/workflows/ruff.yml | 10 + .github/workflows/test.yml | 34 +++ .lintstagedrc.json | 4 - .pre-commit-config.yaml | 10 + .renovaterc.json | 23 +- .vscode/launch.json | 10 +- .vscode/settings.json | 8 +- LICENSE | 4 +- e2e/e2e_utils.py | 13 +- e2e/test_rxdb_dataframe.py | 36 --- e2e/test_rxdb_textcomplete.py | 52 ++++ poetry.lock | 281 +++++------------- pyproject.toml | 19 +- setup.py | 33 -- textcomplete/__init__.py | 29 +- example.py => textcomplete/example.py | 15 +- .../frontend/.npmignore | 0 .../frontend/.prettierignore | 3 +- .../frontend/.prettierrc | 0 textcomplete/frontend/build/index.js | 2 +- .../frontend/jest.config.ts | 0 textcomplete/frontend/package-lock.json | 244 +++++++++++++++ textcomplete/frontend/package.json | 2 + .../@textcomplete+textarea+0.1.13.patch | 14 + textcomplete/frontend/project.json | 8 - textcomplete/frontend/src/helpers.js | 76 +++++ textcomplete/frontend/src/index.js | 108 ++----- 27 files changed, 600 insertions(+), 438 deletions(-) create mode 100644 .github/workflows/ruff.yml create mode 100644 .github/workflows/test.yml delete mode 100644 .lintstagedrc.json create mode 100644 .pre-commit-config.yaml delete mode 100644 e2e/test_rxdb_dataframe.py create mode 100644 e2e/test_rxdb_textcomplete.py delete mode 100644 setup.py rename example.py => textcomplete/example.py (96%) rename .npmignore => textcomplete/frontend/.npmignore (100%) rename .prettierignore => textcomplete/frontend/.prettierignore (85%) rename .prettierrc => textcomplete/frontend/.prettierrc (100%) rename jest.config.ts => textcomplete/frontend/jest.config.ts (100%) create mode 100644 textcomplete/frontend/patches/@textcomplete+textarea+0.1.13.patch delete mode 100644 textcomplete/frontend/project.json create mode 100644 textcomplete/frontend/src/helpers.js diff --git a/.github/workflows/ruff.yml b/.github/workflows/ruff.yml new file mode 100644 index 0000000..6915d87 --- /dev/null +++ b/.github/workflows/ruff.yml @@ -0,0 +1,10 @@ +name: Ruff +on: [push, pull_request] +jobs: + ruff: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: chartboost/ruff-action@v1 + with: + args: 'format --check' \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..ae78c23 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,34 @@ +name: Pytest with Playwright + +on: + pull_request: + branches: + - main + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: [3.11, 3.12] + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + pip install poetry + poetry install + + - name: Install Playwright browsers + run: | + poetry run playwright install + + - name: Run pytest with Playwright + run: | + poetry run pytest e2e/ diff --git a/.lintstagedrc.json b/.lintstagedrc.json deleted file mode 100644 index aef0460..0000000 --- a/.lintstagedrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "*.{ts,js}": ["eslint --fix", "git add"], - "*.{html,css,scss,md,yml}": ["prettier --write", "git add"] -} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..1962bbb --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,10 @@ +repos: +- repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.5.4 + hooks: + # Run the linter. + - id: ruff + args: [ --fix ] + # Run the formatter. + - id: ruff-format \ No newline at end of file diff --git a/.renovaterc.json b/.renovaterc.json index e44d0d1..86e3bae 100644 --- a/.renovaterc.json +++ b/.renovaterc.json @@ -2,16 +2,10 @@ "extends": [ "config:base", "group:all", - "monorepo:angular", "schedule:monthly", ":maintainLockFilesMonthly" ], - "ignoreDeps": [ - "typescript", - "semantic-release", - "@semantic-release/git", - "@semantic-release/changelog" - ], + "ignoreDeps": [], "pinVersions": false, "separatePatchReleases": false, "ignoreUnstable": true, @@ -23,18 +17,5 @@ "peerDependencies": { "versionStrategy": "widen" }, - "packageRules": [ - { - "sourceUrlPrefixes": ["https://github.com/babel/babel"], - "groupName": "babel monorepo" - }, - { - "packagePatterns": ["^eslint"], - "groupName": "eslint" - }, - { - "packagePatterns": ["jest"], - "groupName": "jest" - } - ] + "packageRules": [] } diff --git a/.vscode/launch.json b/.vscode/launch.json index 99ca681..7b5a0ec 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -19,13 +19,17 @@ "request": "launch", "module": "pytest", "args": [ - "${file}" + "${file}", + // "-vv", + // "--headed" ], "env": { "PYTHONPATH": "${workspaceFolder}" }, - "console": "integratedTerminal" + "console": "integratedTerminal", + "justMyCode": true }, + { "name": "Python: Debug Streamlit", "type": "debugpy", @@ -33,7 +37,7 @@ "module": "streamlit", "args": [ "run", - "example.py", + "${workspaceFolder}/textcomplete/example.py", "--server.headless=true", "--browser.gatherUsageStats=false" ], diff --git a/.vscode/settings.json b/.vscode/settings.json index 1d4bad2..73589c0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -14,8 +14,12 @@ "statusBarItem.remoteForeground": "#e7e7e7" }, "peacock.color": "#631661", - "python.defaultInterpreterPath": "/home/voznik/.cache/pypoetry/virtualenvs/streamlit-rxdb-dataframe-zuiqvGqO-py3.10", "flake8.args": ["--max-line-length=100"], "flake8.importStrategy": "fromEnvironment", - "black-formatter.args": ["--line-length=100"] + "black-formatter.args": [ + "--line-length=100" + ], + "python.analysis.extraPaths": [ + "./e2e" + ] } diff --git a/LICENSE b/LICENSE index d7e8cff..3b145f2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,6 @@ -Copyright (c) 2018-2021 Streamlit Inc. +MIT License + +Copyright (c) 2024 VoiceAPI.ai Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/e2e/e2e_utils.py b/e2e/e2e_utils.py index 85fb4b5..16d6c25 100644 --- a/e2e/e2e_utils.py +++ b/e2e/e2e_utils.py @@ -12,7 +12,6 @@ import requests - LOGGER = logging.getLogger(__file__) @@ -27,8 +26,12 @@ def _find_free_port(): class AsyncSubprocess: """A context manager. Wraps subprocess. Popen to capture output safely.""" - def __init__(self, args: typing.List[str], cwd: typing.Optional[str] = None, - env: typing.Optional[typing.Dict[str, str]] = None): + def __init__( + self, + args: typing.List[str], + cwd: typing.Optional[str] = None, + env: typing.Optional[typing.Dict[str, str]] = None, + ): """Initialize an AsyncSubprocess instance. Args: @@ -97,9 +100,7 @@ def stop(self): class StreamlitRunner: """A context manager for running Streamlit scripts.""" - def __init__( - self, script_path: os.PathLike, server_port: typing.Optional[int] = None - ): + def __init__(self, script_path: os.PathLike, server_port: typing.Optional[int] = None): """Initialize a StreamlitRunner instance. Args: diff --git a/e2e/test_rxdb_dataframe.py b/e2e/test_rxdb_dataframe.py deleted file mode 100644 index 9800204..0000000 --- a/e2e/test_rxdb_dataframe.py +++ /dev/null @@ -1,36 +0,0 @@ -from pathlib import Path - -import pytest - -from playwright.sync_api import Page, expect - -from e2e_utils import StreamlitRunner - -ROOT_DIRECTORY = Path(__file__).parent.parent.absolute() -BASIC_EXAMPLE_FILE = ROOT_DIRECTORY / "textcomplete" / "example.py" - -@pytest.fixture(autouse=True, scope="module") -def streamlit_app(): - with StreamlitRunner(BASIC_EXAMPLE_FILE) as runner: - yield runner - - -@pytest.fixture(autouse=True, scope="function") -def go_to_app(page: Page, streamlit_app: StreamlitRunner): - page.goto(streamlit_app.server_url) - # Wait for app to load - page.get_by_role("img", name="Running...").is_hidden() - - -def test_should_render_dataframe(page: Page): - frame = page.frame_locator( - 'iframe[title="textcomplete\\.textcomplete"]' - ) - cell_in_frame = frame.get_by_role("cell", name="Jason") - expect(cell_in_frame).to_be_visible() - - st_table = page.get_by_test_id('stTable') - - frame.get_by_role("button", name="Return dataframe").click() - cell_generated = st_table.get_by_role("cell", name="Jason") - expect(cell_generated).to_be_visible() diff --git a/e2e/test_rxdb_textcomplete.py b/e2e/test_rxdb_textcomplete.py new file mode 100644 index 0000000..27719bb --- /dev/null +++ b/e2e/test_rxdb_textcomplete.py @@ -0,0 +1,52 @@ +import json +from pathlib import Path + +import pytest +from e2e_utils import StreamlitRunner +from playwright.sync_api import Page, expect + +ROOT_DIRECTORY = Path(__file__).parent.parent.absolute() +BASIC_EXAMPLE_FILE = ROOT_DIRECTORY / "textcomplete" / "example.py" + + +@pytest.fixture(autouse=True, scope="module") +def streamlit_app(): + with StreamlitRunner(BASIC_EXAMPLE_FILE, 8502) as runner: + yield runner + + +@pytest.fixture(autouse=True, scope="function") +def go_to_app(page: Page, streamlit_app: StreamlitRunner): + page.goto(streamlit_app.server_url) + # Wait for app to load + page.get_by_role("img", name="Running...").is_hidden() + + +def test_should_render_textcomplete(page: Page): + st_text_area = page.get_by_label("Streamlit Autocomplete") + expect(st_text_area).to_be_visible() + # Retrieve the value of the "data-textcomplete" attribute + data_textcomplete_value = st_text_area.get_attribute("data-textcomplete") + + # Parse the JSON value + assert isinstance( + json.loads(data_textcomplete_value), dict + ), "'data-textcomplete' is not a valid JSON object" + + # Append "s" to the textarea to trigger the dropdown + st_text_area.focus() + st_text_area.evaluate("e => e.setSelectionRange(-1, -1)") + st_text_area.type("s") + # Wait for the dropdown to become visible + dropdown = page.query_selector("ul.textcomplete-dropdown") + dropdown.wait_for_element_state("visible") + # Find li element in dropdown + dropdown_li = dropdown.query_selector("li.textcomplete-item") + assert dropdown_li.inner_text() == "🧑🏻 Mrs. Dennis Schulist" + dropdown_li.press("Enter") + dropdown.wait_for_element_state("hidden") + assert st_text_area.input_value() == "Hello, this is textcomplete demo Mrs. Dennis Schulist" + # Append space to the textarea to make original react component state updated + st_text_area.type(" ") + st_text_area.blur() + assert st_text_area.input_value() == "Hello, this is textcomplete demo Mrs. Dennis Schulist " diff --git a/poetry.lock b/poetry.lock index bb69fad..98de6d4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -43,50 +43,6 @@ tests = ["attrs[tests-no-zope]", "zope-interface"] tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] -[[package]] -name = "black" -version = "23.12.1" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-23.12.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e0aaf6041986767a5e0ce663c7a2f0e9eaf21e6ff87a5f95cbf3675bfd4c41d2"}, - {file = "black-23.12.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c88b3711d12905b74206227109272673edce0cb29f27e1385f33b0163c414bba"}, - {file = "black-23.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920b569dc6b3472513ba6ddea21f440d4b4c699494d2e972a1753cdc25df7b0"}, - {file = "black-23.12.1-cp310-cp310-win_amd64.whl", hash = "sha256:3fa4be75ef2a6b96ea8d92b1587dd8cb3a35c7e3d51f0738ced0781c3aa3a5a3"}, - {file = "black-23.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8d4df77958a622f9b5a4c96edb4b8c0034f8434032ab11077ec6c56ae9f384ba"}, - {file = "black-23.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:602cfb1196dc692424c70b6507593a2b29aac0547c1be9a1d1365f0d964c353b"}, - {file = "black-23.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c4352800f14be5b4864016882cdba10755bd50805c95f728011bcb47a4afd59"}, - {file = "black-23.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:0808494f2b2df923ffc5723ed3c7b096bd76341f6213989759287611e9837d50"}, - {file = "black-23.12.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:25e57fd232a6d6ff3f4478a6fd0580838e47c93c83eaf1ccc92d4faf27112c4e"}, - {file = "black-23.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2d9e13db441c509a3763a7a3d9a49ccc1b4e974a47be4e08ade2a228876500ec"}, - {file = "black-23.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6d1bd9c210f8b109b1762ec9fd36592fdd528485aadb3f5849b2740ef17e674e"}, - {file = "black-23.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:ae76c22bde5cbb6bfd211ec343ded2163bba7883c7bc77f6b756a1049436fbb9"}, - {file = "black-23.12.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1fa88a0f74e50e4487477bc0bb900c6781dbddfdfa32691e780bf854c3b4a47f"}, - {file = "black-23.12.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a4d6a9668e45ad99d2f8ec70d5c8c04ef4f32f648ef39048d010b0689832ec6d"}, - {file = "black-23.12.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b18fb2ae6c4bb63eebe5be6bd869ba2f14fd0259bda7d18a46b764d8fb86298a"}, - {file = "black-23.12.1-cp38-cp38-win_amd64.whl", hash = "sha256:c04b6d9d20e9c13f43eee8ea87d44156b8505ca8a3c878773f68b4e4812a421e"}, - {file = "black-23.12.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3e1b38b3135fd4c025c28c55ddfc236b05af657828a8a6abe5deec419a0b7055"}, - {file = "black-23.12.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4f0031eaa7b921db76decd73636ef3a12c942ed367d8c3841a0739412b260a54"}, - {file = "black-23.12.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97e56155c6b737854e60a9ab1c598ff2533d57e7506d97af5481141671abf3ea"}, - {file = "black-23.12.1-cp39-cp39-win_amd64.whl", hash = "sha256:dd15245c8b68fe2b6bd0f32c1556509d11bb33aec9b5d0866dd8e2ed3dba09c2"}, - {file = "black-23.12.1-py3-none-any.whl", hash = "sha256:78baad24af0f033958cad29731e27363183e140962595def56423e626f4bee3e"}, - {file = "black-23.12.1.tar.gz", hash = "sha256:4ce3ef14ebe8d9509188014d96af1c456a910d5b5cbf434a09fef7e024b3d0d5"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - [[package]] name = "blinker" version = "1.8.2" @@ -100,13 +56,13 @@ files = [ [[package]] name = "cachetools" -version = "5.3.3" +version = "5.4.0" description = "Extensible memoizing collections and decorators" optional = false python-versions = ">=3.7" files = [ - {file = "cachetools-5.3.3-py3-none-any.whl", hash = "sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945"}, - {file = "cachetools-5.3.3.tar.gz", hash = "sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105"}, + {file = "cachetools-5.4.0-py3-none-any.whl", hash = "sha256:3ae3b49a3d5e28a77a0be2b37dbcb89005058959cb2323858c2657c4a8cab474"}, + {file = "cachetools-5.4.0.tar.gz", hash = "sha256:b8adc2e7c07f105ced7bc56dbb6dfbe7c4a00acce20e2227b3f355be89bc6827"}, ] [[package]] @@ -261,36 +217,6 @@ typing-extensions = ">=4.7.0" [package.extras] dev = ["coverage", "pytest (>=7.4.4)"] -[[package]] -name = "flake8" -version = "7.1.0" -description = "the modular source code checker: pep8 pyflakes and co" -optional = false -python-versions = ">=3.8.1" -files = [ - {file = "flake8-7.1.0-py2.py3-none-any.whl", hash = "sha256:2e416edcc62471a64cea09353f4e7bdba32aeb079b6e360554c659a122b1bc6a"}, - {file = "flake8-7.1.0.tar.gz", hash = "sha256:48a07b626b55236e0fb4784ee69a465fbf59d79eec1f5b4785c3d3bc57d17aa5"}, -] - -[package.dependencies] -mccabe = ">=0.7.0,<0.8.0" -pycodestyle = ">=2.12.0,<2.13.0" -pyflakes = ">=3.2.0,<3.3.0" - -[[package]] -name = "flake8-annotations-complexity" -version = "0.0.8" -description = "A flake8 extension that checks for type annotations complexity" -optional = false -python-versions = ">=3.7" -files = [ - {file = "flake8_annotations_complexity-0.0.8-py3-none-any.whl", hash = "sha256:44e299dac0ab64f3af4b478fac7feb635c113a606036de8b39dadab3531da7ed"}, - {file = "flake8_annotations_complexity-0.0.8.tar.gz", hash = "sha256:8914e76e31672c4063c928b0a250db6b935a16d1799de10457958a71d11bb665"}, -] - -[package.dependencies] -flake8 = "*" - [[package]] name = "gitdb" version = "4.0.11" @@ -575,17 +501,6 @@ files = [ {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, ] -[[package]] -name = "mccabe" -version = "0.7.0" -description = "McCabe checker, plugin for flake8" -optional = false -python-versions = ">=3.6" -files = [ - {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, - {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, -] - [[package]] name = "mdurl" version = "0.1.2" @@ -599,43 +514,43 @@ files = [ [[package]] name = "mypy" -version = "1.10.1" +version = "1.11.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e36f229acfe250dc660790840916eb49726c928e8ce10fbdf90715090fe4ae02"}, - {file = "mypy-1.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:51a46974340baaa4145363b9e051812a2446cf583dfaeba124af966fa44593f7"}, - {file = "mypy-1.10.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:901c89c2d67bba57aaaca91ccdb659aa3a312de67f23b9dfb059727cce2e2e0a"}, - {file = "mypy-1.10.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0cd62192a4a32b77ceb31272d9e74d23cd88c8060c34d1d3622db3267679a5d9"}, - {file = "mypy-1.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:a2cbc68cb9e943ac0814c13e2452d2046c2f2b23ff0278e26599224cf164e78d"}, - {file = "mypy-1.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bd6f629b67bb43dc0d9211ee98b96d8dabc97b1ad38b9b25f5e4c4d7569a0c6a"}, - {file = "mypy-1.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1bbb3a6f5ff319d2b9d40b4080d46cd639abe3516d5a62c070cf0114a457d84"}, - {file = "mypy-1.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8edd4e9bbbc9d7b79502eb9592cab808585516ae1bcc1446eb9122656c6066f"}, - {file = "mypy-1.10.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6166a88b15f1759f94a46fa474c7b1b05d134b1b61fca627dd7335454cc9aa6b"}, - {file = "mypy-1.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:5bb9cd11c01c8606a9d0b83ffa91d0b236a0e91bc4126d9ba9ce62906ada868e"}, - {file = "mypy-1.10.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:d8681909f7b44d0b7b86e653ca152d6dff0eb5eb41694e163c6092124f8246d7"}, - {file = "mypy-1.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:378c03f53f10bbdd55ca94e46ec3ba255279706a6aacaecac52ad248f98205d3"}, - {file = "mypy-1.10.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bacf8f3a3d7d849f40ca6caea5c055122efe70e81480c8328ad29c55c69e93e"}, - {file = "mypy-1.10.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:701b5f71413f1e9855566a34d6e9d12624e9e0a8818a5704d74d6b0402e66c04"}, - {file = "mypy-1.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:3c4c2992f6ea46ff7fce0072642cfb62af7a2484efe69017ed8b095f7b39ef31"}, - {file = "mypy-1.10.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:604282c886497645ffb87b8f35a57ec773a4a2721161e709a4422c1636ddde5c"}, - {file = "mypy-1.10.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37fd87cab83f09842653f08de066ee68f1182b9b5282e4634cdb4b407266bade"}, - {file = "mypy-1.10.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8addf6313777dbb92e9564c5d32ec122bf2c6c39d683ea64de6a1fd98b90fe37"}, - {file = "mypy-1.10.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5cc3ca0a244eb9a5249c7c583ad9a7e881aa5d7b73c35652296ddcdb33b2b9c7"}, - {file = "mypy-1.10.1-cp38-cp38-win_amd64.whl", hash = "sha256:1b3a2ffce52cc4dbaeee4df762f20a2905aa171ef157b82192f2e2f368eec05d"}, - {file = "mypy-1.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fe85ed6836165d52ae8b88f99527d3d1b2362e0cb90b005409b8bed90e9059b3"}, - {file = "mypy-1.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c2ae450d60d7d020d67ab440c6e3fae375809988119817214440033f26ddf7bf"}, - {file = "mypy-1.10.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6be84c06e6abd72f960ba9a71561c14137a583093ffcf9bbfaf5e613d63fa531"}, - {file = "mypy-1.10.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2189ff1e39db399f08205e22a797383613ce1cb0cb3b13d8bcf0170e45b96cc3"}, - {file = "mypy-1.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:97a131ee36ac37ce9581f4220311247ab6cba896b4395b9c87af0675a13a755f"}, - {file = "mypy-1.10.1-py3-none-any.whl", hash = "sha256:71d8ac0b906354ebda8ef1673e5fde785936ac1f29ff6987c7483cfbd5a4235a"}, - {file = "mypy-1.10.1.tar.gz", hash = "sha256:1f8f492d7db9e3593ef42d4f115f04e556130f2819ad33ab84551403e97dd4c0"}, + {file = "mypy-1.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3824187c99b893f90c845bab405a585d1ced4ff55421fdf5c84cb7710995229"}, + {file = "mypy-1.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:96f8dbc2c85046c81bcddc246232d500ad729cb720da4e20fce3b542cab91287"}, + {file = "mypy-1.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a5d8d8dd8613a3e2be3eae829ee891b6b2de6302f24766ff06cb2875f5be9c6"}, + {file = "mypy-1.11.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72596a79bbfb195fd41405cffa18210af3811beb91ff946dbcb7368240eed6be"}, + {file = "mypy-1.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:35ce88b8ed3a759634cb4eb646d002c4cef0a38f20565ee82b5023558eb90c00"}, + {file = "mypy-1.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:98790025861cb2c3db8c2f5ad10fc8c336ed2a55f4daf1b8b3f877826b6ff2eb"}, + {file = "mypy-1.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:25bcfa75b9b5a5f8d67147a54ea97ed63a653995a82798221cca2a315c0238c1"}, + {file = "mypy-1.11.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bea2a0e71c2a375c9fa0ede3d98324214d67b3cbbfcbd55ac8f750f85a414e3"}, + {file = "mypy-1.11.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d2b3d36baac48e40e3064d2901f2fbd2a2d6880ec6ce6358825c85031d7c0d4d"}, + {file = "mypy-1.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:d8e2e43977f0e09f149ea69fd0556623919f816764e26d74da0c8a7b48f3e18a"}, + {file = "mypy-1.11.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:1d44c1e44a8be986b54b09f15f2c1a66368eb43861b4e82573026e04c48a9e20"}, + {file = "mypy-1.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:cea3d0fb69637944dd321f41bc896e11d0fb0b0aa531d887a6da70f6e7473aba"}, + {file = "mypy-1.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a83ec98ae12d51c252be61521aa5731f5512231d0b738b4cb2498344f0b840cd"}, + {file = "mypy-1.11.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c7b73a856522417beb78e0fb6d33ef89474e7a622db2653bc1285af36e2e3e3d"}, + {file = "mypy-1.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:f2268d9fcd9686b61ab64f077be7ffbc6fbcdfb4103e5dd0cc5eaab53a8886c2"}, + {file = "mypy-1.11.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:940bfff7283c267ae6522ef926a7887305945f716a7704d3344d6d07f02df850"}, + {file = "mypy-1.11.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:14f9294528b5f5cf96c721f231c9f5b2733164e02c1c018ed1a0eff8a18005ac"}, + {file = "mypy-1.11.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d7b54c27783991399046837df5c7c9d325d921394757d09dbcbf96aee4649fe9"}, + {file = "mypy-1.11.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:65f190a6349dec29c8d1a1cd4aa71284177aee5949e0502e6379b42873eddbe7"}, + {file = "mypy-1.11.0-cp38-cp38-win_amd64.whl", hash = "sha256:dbe286303241fea8c2ea5466f6e0e6a046a135a7e7609167b07fd4e7baf151bf"}, + {file = "mypy-1.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:104e9c1620c2675420abd1f6c44bab7dd33cc85aea751c985006e83dcd001095"}, + {file = "mypy-1.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f006e955718ecd8d159cee9932b64fba8f86ee6f7728ca3ac66c3a54b0062abe"}, + {file = "mypy-1.11.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:becc9111ca572b04e7e77131bc708480cc88a911adf3d0239f974c034b78085c"}, + {file = "mypy-1.11.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6801319fe76c3f3a3833f2b5af7bd2c17bb93c00026a2a1b924e6762f5b19e13"}, + {file = "mypy-1.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:c1a184c64521dc549324ec6ef7cbaa6b351912be9cb5edb803c2808a0d7e85ac"}, + {file = "mypy-1.11.0-py3-none-any.whl", hash = "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace"}, + {file = "mypy-1.11.0.tar.gz", hash = "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538"}, ] [package.dependencies] mypy-extensions = ">=1.0.0" -typing-extensions = ">=4.1.0" +typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] @@ -791,17 +706,6 @@ sql-other = ["SQLAlchemy (>=2.0.0)", "adbc-driver-postgresql (>=0.8.0)", "adbc-d test = ["hypothesis (>=6.46.1)", "pytest (>=7.3.2)", "pytest-xdist (>=2.2.0)"] xml = ["lxml (>=4.9.2)"] -[[package]] -name = "pathspec" -version = "0.12.1" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.8" -files = [ - {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, - {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, -] - [[package]] name = "pillow" version = "10.4.0" @@ -899,22 +803,6 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa typing = ["typing-extensions"] xmp = ["defusedxml"] -[[package]] -name = "platformdirs" -version = "4.2.2" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -optional = false -python-versions = ">=3.8" -files = [ - {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, - {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, -] - -[package.extras] -docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] -type = ["mypy (>=1.8)"] - [[package]] name = "playwright" version = "1.45.0" @@ -972,62 +860,54 @@ files = [ [[package]] name = "pyarrow" -version = "16.1.0" +version = "17.0.0" description = "Python library for Apache Arrow" optional = false python-versions = ">=3.8" files = [ - {file = "pyarrow-16.1.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:17e23b9a65a70cc733d8b738baa6ad3722298fa0c81d88f63ff94bf25eaa77b9"}, - {file = "pyarrow-16.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4740cc41e2ba5d641071d0ab5e9ef9b5e6e8c7611351a5cb7c1d175eaf43674a"}, - {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:98100e0268d04e0eec47b73f20b39c45b4006f3c4233719c3848aa27a03c1aef"}, - {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68f409e7b283c085f2da014f9ef81e885d90dcd733bd648cfba3ef265961848"}, - {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:a8914cd176f448e09746037b0c6b3a9d7688cef451ec5735094055116857580c"}, - {file = "pyarrow-16.1.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:48be160782c0556156d91adbdd5a4a7e719f8d407cb46ae3bb4eaee09b3111bd"}, - {file = "pyarrow-16.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:9cf389d444b0f41d9fe1444b70650fea31e9d52cfcb5f818b7888b91b586efff"}, - {file = "pyarrow-16.1.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:d0ebea336b535b37eee9eee31761813086d33ed06de9ab6fc6aaa0bace7b250c"}, - {file = "pyarrow-16.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e73cfc4a99e796727919c5541c65bb88b973377501e39b9842ea71401ca6c1c"}, - {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf9251264247ecfe93e5f5a0cd43b8ae834f1e61d1abca22da55b20c788417f6"}, - {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddf5aace92d520d3d2a20031d8b0ec27b4395cab9f74e07cc95edf42a5cc0147"}, - {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:25233642583bf658f629eb230b9bb79d9af4d9f9229890b3c878699c82f7d11e"}, - {file = "pyarrow-16.1.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a33a64576fddfbec0a44112eaf844c20853647ca833e9a647bfae0582b2ff94b"}, - {file = "pyarrow-16.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:185d121b50836379fe012753cf15c4ba9638bda9645183ab36246923875f8d1b"}, - {file = "pyarrow-16.1.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:2e51ca1d6ed7f2e9d5c3c83decf27b0d17bb207a7dea986e8dc3e24f80ff7d6f"}, - {file = "pyarrow-16.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06ebccb6f8cb7357de85f60d5da50e83507954af617d7b05f48af1621d331c9a"}, - {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b04707f1979815f5e49824ce52d1dceb46e2f12909a48a6a753fe7cafbc44a0c"}, - {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0d32000693deff8dc5df444b032b5985a48592c0697cb6e3071a5d59888714e2"}, - {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:8785bb10d5d6fd5e15d718ee1d1f914fe768bf8b4d1e5e9bf253de8a26cb1628"}, - {file = "pyarrow-16.1.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:e1369af39587b794873b8a307cc6623a3b1194e69399af0efd05bb202195a5a7"}, - {file = "pyarrow-16.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:febde33305f1498f6df85e8020bca496d0e9ebf2093bab9e0f65e2b4ae2b3444"}, - {file = "pyarrow-16.1.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b5f5705ab977947a43ac83b52ade3b881eb6e95fcc02d76f501d549a210ba77f"}, - {file = "pyarrow-16.1.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0d27bf89dfc2576f6206e9cd6cf7a107c9c06dc13d53bbc25b0bd4556f19cf5f"}, - {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d07de3ee730647a600037bc1d7b7994067ed64d0eba797ac74b2bc77384f4c2"}, - {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fbef391b63f708e103df99fbaa3acf9f671d77a183a07546ba2f2c297b361e83"}, - {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:19741c4dbbbc986d38856ee7ddfdd6a00fc3b0fc2d928795b95410d38bb97d15"}, - {file = "pyarrow-16.1.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:f2c5fb249caa17b94e2b9278b36a05ce03d3180e6da0c4c3b3ce5b2788f30eed"}, - {file = "pyarrow-16.1.0-cp38-cp38-win_amd64.whl", hash = "sha256:e6b6d3cd35fbb93b70ade1336022cc1147b95ec6af7d36906ca7fe432eb09710"}, - {file = "pyarrow-16.1.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:18da9b76a36a954665ccca8aa6bd9f46c1145f79c0bb8f4f244f5f8e799bca55"}, - {file = "pyarrow-16.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:99f7549779b6e434467d2aa43ab2b7224dd9e41bdde486020bae198978c9e05e"}, - {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f07fdffe4fd5b15f5ec15c8b64584868d063bc22b86b46c9695624ca3505b7b4"}, - {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ddfe389a08ea374972bd4065d5f25d14e36b43ebc22fc75f7b951f24378bf0b5"}, - {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:3b20bd67c94b3a2ea0a749d2a5712fc845a69cb5d52e78e6449bbd295611f3aa"}, - {file = "pyarrow-16.1.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:ba8ac20693c0bb0bf4b238751d4409e62852004a8cf031c73b0e0962b03e45e3"}, - {file = "pyarrow-16.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:31a1851751433d89a986616015841977e0a188662fcffd1a5677453f1df2de0a"}, - {file = "pyarrow-16.1.0.tar.gz", hash = "sha256:15fbb22ea96d11f0b5768504a3f961edab25eaf4197c341720c4a387f6c60315"}, + {file = "pyarrow-17.0.0-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a5c8b238d47e48812ee577ee20c9a2779e6a5904f1708ae240f53ecbee7c9f07"}, + {file = "pyarrow-17.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db023dc4c6cae1015de9e198d41250688383c3f9af8f565370ab2b4cb5f62655"}, + {file = "pyarrow-17.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da1e060b3876faa11cee287839f9cc7cdc00649f475714b8680a05fd9071d545"}, + {file = "pyarrow-17.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75c06d4624c0ad6674364bb46ef38c3132768139ddec1c56582dbac54f2663e2"}, + {file = "pyarrow-17.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:fa3c246cc58cb5a4a5cb407a18f193354ea47dd0648194e6265bd24177982fe8"}, + {file = "pyarrow-17.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:f7ae2de664e0b158d1607699a16a488de3d008ba99b3a7aa5de1cbc13574d047"}, + {file = "pyarrow-17.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:5984f416552eea15fd9cee03da53542bf4cddaef5afecefb9aa8d1010c335087"}, + {file = "pyarrow-17.0.0-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:1c8856e2ef09eb87ecf937104aacfa0708f22dfeb039c363ec99735190ffb977"}, + {file = "pyarrow-17.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2e19f569567efcbbd42084e87f948778eb371d308e137a0f97afe19bb860ccb3"}, + {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b244dc8e08a23b3e352899a006a26ae7b4d0da7bb636872fa8f5884e70acf15"}, + {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b72e87fe3e1db343995562f7fff8aee354b55ee83d13afba65400c178ab2597"}, + {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:dc5c31c37409dfbc5d014047817cb4ccd8c1ea25d19576acf1a001fe07f5b420"}, + {file = "pyarrow-17.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:e3343cb1e88bc2ea605986d4b94948716edc7a8d14afd4e2c097232f729758b4"}, + {file = "pyarrow-17.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:a27532c38f3de9eb3e90ecab63dfda948a8ca859a66e3a47f5f42d1e403c4d03"}, + {file = "pyarrow-17.0.0-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:9b8a823cea605221e61f34859dcc03207e52e409ccf6354634143e23af7c8d22"}, + {file = "pyarrow-17.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f1e70de6cb5790a50b01d2b686d54aaf73da01266850b05e3af2a1bc89e16053"}, + {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0071ce35788c6f9077ff9ecba4858108eebe2ea5a3f7cf2cf55ebc1dbc6ee24a"}, + {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:757074882f844411fcca735e39aae74248a1531367a7c80799b4266390ae51cc"}, + {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:9ba11c4f16976e89146781a83833df7f82077cdab7dc6232c897789343f7891a"}, + {file = "pyarrow-17.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b0c6ac301093b42d34410b187bba560b17c0330f64907bfa4f7f7f2444b0cf9b"}, + {file = "pyarrow-17.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:392bc9feabc647338e6c89267635e111d71edad5fcffba204425a7c8d13610d7"}, + {file = "pyarrow-17.0.0-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:af5ff82a04b2171415f1410cff7ebb79861afc5dae50be73ce06d6e870615204"}, + {file = "pyarrow-17.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:edca18eaca89cd6382dfbcff3dd2d87633433043650c07375d095cd3517561d8"}, + {file = "pyarrow-17.0.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c7916bff914ac5d4a8fe25b7a25e432ff921e72f6f2b7547d1e325c1ad9d155"}, + {file = "pyarrow-17.0.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f553ca691b9e94b202ff741bdd40f6ccb70cdd5fbf65c187af132f1317de6145"}, + {file = "pyarrow-17.0.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:0cdb0e627c86c373205a2f94a510ac4376fdc523f8bb36beab2e7f204416163c"}, + {file = "pyarrow-17.0.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:d7d192305d9d8bc9082d10f361fc70a73590a4c65cf31c3e6926cd72b76bc35c"}, + {file = "pyarrow-17.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:02dae06ce212d8b3244dd3e7d12d9c4d3046945a5933d28026598e9dbbda1fca"}, + {file = "pyarrow-17.0.0-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:13d7a460b412f31e4c0efa1148e1d29bdf18ad1411eb6757d38f8fbdcc8645fb"}, + {file = "pyarrow-17.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:9b564a51fbccfab5a04a80453e5ac6c9954a9c5ef2890d1bcf63741909c3f8df"}, + {file = "pyarrow-17.0.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32503827abbc5aadedfa235f5ece8c4f8f8b0a3cf01066bc8d29de7539532687"}, + {file = "pyarrow-17.0.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a155acc7f154b9ffcc85497509bcd0d43efb80d6f733b0dc3bb14e281f131c8b"}, + {file = "pyarrow-17.0.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:dec8d129254d0188a49f8a1fc99e0560dc1b85f60af729f47de4046015f9b0a5"}, + {file = "pyarrow-17.0.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:a48ddf5c3c6a6c505904545c25a4ae13646ae1f8ba703c4df4a1bfe4f4006bda"}, + {file = "pyarrow-17.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:42bf93249a083aca230ba7e2786c5f673507fa97bbd9725a1e2754715151a204"}, + {file = "pyarrow-17.0.0.tar.gz", hash = "sha256:4beca9521ed2c0921c1023e68d097d0299b62c362639ea315572a58f3f50fd28"}, ] [package.dependencies] numpy = ">=1.16.6" -[[package]] -name = "pycodestyle" -version = "2.12.0" -description = "Python style guide checker" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pycodestyle-2.12.0-py2.py3-none-any.whl", hash = "sha256:949a39f6b86c3e1515ba1787c2022131d165a8ad271b11370a8819aa070269e4"}, - {file = "pycodestyle-2.12.0.tar.gz", hash = "sha256:442f950141b4f43df752dd303511ffded3a04c2b6fb7f65980574f0c31e6e79c"}, -] +[package.extras] +test = ["cffi", "hypothesis", "pandas", "pytest", "pytz"] [[package]] name = "pydeck" @@ -1065,17 +945,6 @@ typing-extensions = "*" [package.extras] dev = ["black", "build", "flake8", "flake8-black", "isort", "jupyter-console", "mkdocs", "mkdocs-include-markdown-plugin", "mkdocstrings[python]", "pytest", "pytest-asyncio", "pytest-trio", "sphinx", "toml", "tox", "trio", "trio", "trio-typing", "twine", "twisted", "validate-pyproject[all]"] -[[package]] -name = "pyflakes" -version = "3.2.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.8" -files = [ - {file = "pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a"}, - {file = "pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f"}, -] - [[package]] name = "pygments" version = "2.18.0" @@ -1130,13 +999,13 @@ test = ["black (>=22.1.0)", "flake8 (>=4.0.1)", "pre-commit (>=2.17.0)", "pytest [[package]] name = "pytest-playwright" -version = "0.4.4" +version = "0.5.1" description = "A pytest wrapper with fixtures for Playwright to automate web browsers" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-playwright-0.4.4.tar.gz", hash = "sha256:5488db4cc49028491c5130af0a2bb6b1d0b222a202217f6d14491d4c9aa67ff9"}, - {file = "pytest_playwright-0.4.4-py3-none-any.whl", hash = "sha256:df306f3a60a8631a3cfde1b95a2ed5a89203a3408dfa1154de049ca7de87c90b"}, + {file = "pytest-playwright-0.5.1.tar.gz", hash = "sha256:6b0683cbacd060f338b37d0c2cdac25d841e14f1440e986efcceaacd3d61a268"}, + {file = "pytest_playwright-0.5.1-py3-none-any.whl", hash = "sha256:54eb12742de16bf50d9630fe06ac398727e52d5c1e55269acb37e1ede91d9e00"}, ] [package.dependencies] @@ -1560,4 +1429,4 @@ watchmedo = ["PyYAML (>=3.10)"] [metadata] lock-version = "2.0" python-versions = "^3.11" -content-hash = "f45f875c647da449b287bfb8297125bbc5cab54332d1609269cd5929142f4860" +content-hash = "7c1478f869516e83ae6d5d9b65876bee2b1d2609354272631be51e9d6c733ad4" diff --git a/pyproject.toml b/pyproject.toml index f4025e4..45f32bd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,23 +12,20 @@ packages = [{ include = "textcomplete" }] [tool.poetry.dependencies] python = "^3.11" -pytest-playwright = "^0.4.4" -streamlit = "^1.31.0" -playwright = "^1.41.2" +streamlit = "^1.36.0" pandas = "^2.2.2" - emoji = "^2.12.1" + [build-system] requires = ["poetry-core"] build-backend = "poetry.core.masonry.api" [tool.poetry.group.dev.dependencies] -pytest = "^7.1.3" -black = "^23.1.0" -isort = "^5.12.0" -mypy = "^1.0.0" -flake8 = "^7.0.0" -flake8-annotations-complexity = "^0.0.8" +playwright = "^1.45.0" +pytest-playwright = "^0.5.1" +pytest = "^7.4.4" +isort = "^5.13.2" +mypy = "^1.11.0" [tool.isort] profile = "black" @@ -75,7 +72,7 @@ exclude = [ ".direnv", "streamlit_patches.py", ] -target-version = "py310" +target-version = "py311" ignore = ["E501"] line-length = 100 select = ["B", "E", "F", "W", "I"] diff --git a/setup.py b/setup.py deleted file mode 100644 index 0f59811..0000000 --- a/setup.py +++ /dev/null @@ -1,33 +0,0 @@ -import setuptools - -setuptools.setup( - name="streamlit-textcomplete", - version="0.0.1", - author="voznik", - author_email="", - author_url="github.com/voznik", - description="Textcomplete editor for HTMLTextAreaElement.", - long_description="Textcomplete editor for HTMLTextAreaElement.", - long_description_content_type="text/plain", - url="", - packages=setuptools.find_packages(), - include_package_data=True, - classifiers=[], - python_requires=">=3.7", - install_requires=[ - # By definition, a Custom Component depends on Streamlit. - # If your component has other Python dependencies, list - # them here. - "streamlit >= 0.66", - ], - extras_require={ - "devel": [ - "wheel", - "pytest==7.4.0", - "playwright==1.39.0", - "requests==2.31.0", - "pytest-playwright-snapshot==1.0", - "pytest-rerunfailures==12.0", - ] - } -) diff --git a/textcomplete/__init__.py b/textcomplete/__init__.py index 9c31ec9..d525070 100644 --- a/textcomplete/__init__.py +++ b/textcomplete/__init__.py @@ -1,5 +1,4 @@ import os -import pandas as pd # import pyarrow as pa # from streamlit.proto.Components_pb2 import SpecialArg @@ -12,22 +11,23 @@ List, Literal, Optional, - TypeVar, TypedDict, + TypeVar, Union, ) + +import pandas as pd import streamlit.components.v1 as components +from streamlit import session_state as ss # noqa: F401 from streamlit.elements.widgets.text_widgets import ( # noqa: F401 - LabelVisibility, - WidgetCallback, - WidgetArgs, - WidgetKwargs, Key, + LabelVisibility, SupportsStr, TextWidgetsMixin, + WidgetArgs, + WidgetCallback, + WidgetKwargs, ) -from streamlit import session_state as ss # noqa: F401 - from streamlit.runtime.caching import cache_data # noqa: F401 # Create a _RELEASE constant. We'll set this to False while we're developing @@ -84,7 +84,7 @@ def __init__( index: str = None, id: str = None, data: List[Dict[str, Any]] | pd.DataFrame = None, - comparator_keys: List[str] = [], + comparator_keys: List[str] = [], # noqa: B006 ) -> None: self.match = match self.search = search @@ -130,7 +130,7 @@ def textcomplete( max_count: int = 10, placement: Literal["auto"] | Literal["top"] | Literal["bottom"] = "bottom", rotate: bool = False, - # style: str | None = None, # TODO: CSSStyleDeclaration + stop_enter_propagation: bool = False, dynamic_width: bool = True, dropdown_style: str = "", ) -> Optional[TextcompleteResult]: @@ -160,6 +160,7 @@ def textcomplete( area_label=area_label, strategies=[strategy.to_dict() for strategy in strategies], dropdown_option=dropdown_option, + stop_enter_propagation=stop_enter_propagation, ) if on_select and result: @@ -167,13 +168,13 @@ def textcomplete( # We could modify the value returned from the component if we wanted. # There's no need to do this in our simple example - but it's an option. - return result + # return result __title__ = "Streamlit Textcomplete" -__desc__ = "Textcomplete editor for HTMLTextAreaElement." -__icon__ = "🏦" +__desc__ = "Streamlit autocomplete Textcomplete editor for HTMLTextAreaElement" +__icon__ = "📝" # __examples__ = [example] __author__ = "voznik" -__streamlit_cloud_url__ = "https://st-textcomplete.streamlitapp.com/" +__streamlit_cloud_url__ = "https://textcomplete.streamlitapp.com/" __github_repo__ = "voznik/streamlit-textcomplete" diff --git a/example.py b/textcomplete/example.py similarity index 96% rename from example.py rename to textcomplete/example.py index 529a622..eea6512 100644 --- a/example.py +++ b/textcomplete/example.py @@ -1,11 +1,10 @@ import streamlit as st -import pandas as pd from emoji.unicode_codes.data_dict import EMOJI_DATA # from streamlit.runtime.caching import cache_data from textcomplete import ( - TextcompleteResult, StrategyProps, + TextcompleteResult, textcomplete, ) @@ -47,13 +46,14 @@ def on_change(): - print(st.session_state.txt) + print(st.session_state["txt"]) def on_select(textcomplete_result: TextcompleteResult): searchResult = textcomplete_result.get("searchResult", "") text = textcomplete_result.get("text", "") print(searchResult, text) + st.session_state["txt"] = text with col1: @@ -78,6 +78,7 @@ def on_select(textcomplete_result: TextcompleteResult): strategies=[username_strategy, emoji_strategy], on_select=on_select, max_count=5, + stop_enter_propagation=True, ) with col2: @@ -97,11 +98,10 @@ def on_select(textcomplete_result: TextcompleteResult): strategies=[username_strategy, emoji_strategy], on_select=on_select, max_count=10, - placement="bottom", + stop_enter_propagation=True, ) -st.markdown( - """# Streamlit Autocomplete Text with Textcomplete +st.markdown(r"""# Streamlit Autocomplete Text with Textcomplete ## Vendor @@ -215,5 +215,4 @@ def on_select(textcomplete_result: TextcompleteResult): } } ``` -""" -) # noqa: F401 +""") # noqa: F401 diff --git a/.npmignore b/textcomplete/frontend/.npmignore similarity index 100% rename from .npmignore rename to textcomplete/frontend/.npmignore diff --git a/.prettierignore b/textcomplete/frontend/.prettierignore similarity index 85% rename from .prettierignore rename to textcomplete/frontend/.prettierignore index b81d297..af82fef 100644 --- a/.prettierignore +++ b/textcomplete/frontend/.prettierignore @@ -1,5 +1,4 @@ # Add files here to ignore them from prettier formatting /dist -/coverage - +/build diff --git a/.prettierrc b/textcomplete/frontend/.prettierrc similarity index 100% rename from .prettierrc rename to textcomplete/frontend/.prettierrc diff --git a/textcomplete/frontend/build/index.js b/textcomplete/frontend/build/index.js index 48ba2fe..cdb0ae0 100644 --- a/textcomplete/frontend/build/index.js +++ b/textcomplete/frontend/build/index.js @@ -1,2 +1,2 @@ -(()=>{var e={344:function(e,t,n){"use strict";function r(e,t){for(var n=0;no&&(e.left=o-r),this.el.style.left="".concat(e.left,"px")}else e.right&&(e.right-r<0&&(e.right=0),this.el.style.right="".concat(e.right,"px"));var i=!1,a=this.option.placement||t.DEFAULT_DROPDOWN_PLACEMENT;if("auto"===a){var s=this.items.length*e.lineHeight;i=null!=e.clientTop&&e.clientTop+s>n.clientHeight}"top"===a||i?(this.el.style.bottom="".concat(n.clientHeight-e.top+e.lineHeight,"px"),this.el.style.top="auto"):(this.el.style.top="".concat(e.top,"px"),this.el.style.bottom="auto")}return this}},{key:"getNextActiveIndex",value:function(){if(null==this.activeIndex)throw Error();return this.activeIndex0)||void 0===arguments[0]||arguments[0];return this.completer.destroy(),this.dropdown.destroy(),e&&this.editor.destroy(),this.stopListening(),this}},{key:"isShown",value:function(){return this.dropdown.isShown()}},{key:"hide",value:function(){return this.dropdown.hide(),this}},{key:"trigger",value:function(e){return this.isQueryInFlight?this.nextPendingQuery=e:(this.isQueryInFlight=!0,this.nextPendingQuery=null,this.completer.run(e)),this}},{key:"startListening",value:function(){var e=this;this.editor.on("move",this.handleMove).on("enter",this.handleEnter).on("esc",this.handleEsc).on("change",this.handleChange),this.dropdown.on("select",this.handleSelect);var t=!0,n=!1,r=void 0;try{for(var o,i,a,s=u[Symbol.iterator]();!(t=(a=s.next()).done);t=!0)i=this,function(){var t=a.value;i.dropdown.on(t,function(n){return e.emit(t,n)})}()}catch(e){n=!0,r=e}finally{try{!t&&null!=s.return&&s.return()}finally{if(n)throw r}}this.completer.on("hit",this.handleHit),null===(o=this.dropdown.el.ownerDocument.defaultView)||void 0===o||o.addEventListener("resize",this.handleResize)}},{key:"stopListening",value:function(){var e;null===(e=this.dropdown.el.ownerDocument.defaultView)||void 0===e||e.removeEventListener("resize",this.handleResize),this.completer.removeAllListeners(),this.dropdown.removeAllListeners(),this.editor.removeListener("move",this.handleMove).removeListener("enter",this.handleEnter).removeListener("esc",this.handleEsc).removeListener("change",this.handleChange)}}],r(a.prototype,l),h}(a.EventEmitter);t.Textcomplete=l},973:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var o=Object.getOwnPropertyDescriptor(t,n);(!o||("get"in o?!t.__esModule:o.writable||o.configurable))&&(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,o)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"!==n&&!Object.prototype.hasOwnProperty.call(t,n)&&r(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),o(n(344),t),o(n(329),t),o(n(937),t),o(n(363),t),o(n(134),t),o(n(946),t),o(n(125),t)},125:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.createCustomEvent=void 0;var n="undefined"!=typeof window&&!!window.CustomEvent;t.createCustomEvent=function(e,t){if(n)return new CustomEvent(e,t);var r=document.createEvent("CustomEvent");return r.initCustomEvent(e,!1,(null==t?void 0:t.cancelable)||!1,(null==t?void 0:t.detail)||void 0),r}},248:function(e){"use strict";var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function i(e,t,r,i,a){if("function"!=typeof r)throw TypeError("The listener must be a function");var s=new o(r,i||e,a),c=n?n+t:t;return e._events[c]?e._events[c].fn?e._events[c]=[e._events[c],s]:e._events[c].push(s):(e._events[c]=s,e._eventsCount++),e}function a(e,t){0==--e._eventsCount?e._events=new r:delete e._events[t]}function s(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),!new r().__proto__&&(n=!1)),s.prototype.eventNames=function(){var e,r,o=[];if(0===this._eventsCount)return o;for(r in e=this._events)t.call(e,r)&&o.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?o.concat(Object.getOwnPropertySymbols(e)):o},s.prototype.listeners=function(e){var t=n?n+e:e,r=this._events[t];if(!r)return[];if(r.fn)return[r.fn];for(var o=0,i=r.length,a=Array(i);oparseInt(l.height)&&(u.overflowY="scroll"):u.overflow="hidden",c.textContent=e.value.substring(0,o),f&&(c.textContent=c.textContent.replace(/\s/g,"\xa0"));var d=document.createElement("span");d.textContent=e.value.substring(o)||".",c.appendChild(d);var h={top:d.offsetTop+parseInt(l.borderTopWidth),left:d.offsetLeft+parseInt(l.borderLeftWidth),height:parseInt(l.lineHeight)};return a?d.style.backgroundColor="#aaa":document.body.removeChild(c),h}void 0!==e.exports?e.exports=o:n&&(window.getCaretCoordinates=o)}()},460:function(e,t,n){"use strict";function r(e,t){return null!=t&&"undefined"!=typeof Symbol&&t[Symbol.hasInstance]?!!t[Symbol.hasInstance](e):e instanceof t}n.d(t,{l:function(){return s}});var o,i,a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0?e.argsDataframeToObject(t.dfs):{};n=a(a({},n),r);var o=!!t.disabled,i=t.theme;i&&c(i);var s={disabled:o,args:n,theme:i},u=new CustomEvent(e.RENDER_EVENT,{detail:s});e.events.dispatchEvent(u)},e.argsDataframeToObject=function(e){return null},e.toArrowTable=function(e){return null},e.sendBackMsg=function(e,t){window.parent.postMessage(a({isStreamlitMessage:!0,type:e},t),"*")},e}(),c=function(e){var t=document.createElement("style");document.head.appendChild(t),t.innerHTML="\n :root {\n --primary-color: ".concat(e.primaryColor,";\n --background-color: ").concat(e.backgroundColor,";\n --secondary-background-color: ").concat(e.secondaryBackgroundColor,";\n --text-color: ").concat(e.textColor,";\n --font: ").concat(e.font,";\n }\n\n body {\n background-color: var(--background-color);\n color: var(--text-color);\n }\n ")}},471:function(e,t,n){"use strict";function r(e,t,n){let r=e.value,o=t+(n||""),i=document.activeElement,a=0,s=0;for(;a=0&&o.length-s-1>=0&&r[r.length-s-1]===o[o.length-s-1];)s++;a=Math.min(a,Math.min(r.length,o.length)-s),e.setSelectionRange(a,r.length-s);let c=o.substring(a,o.length-s);if(e.focus(),!document.execCommand("insertText",!1,c)){e.value=o;let t=document.createEvent("Event");t.initEvent("input",!0,!0),e.dispatchEvent(t)}return e.setSelectionRange(t.length,t.length),i.focus(),e}function o(e,t,n){let o=e.selectionEnd,i=e.value.substr(0,e.selectionStart)+t,a=e.value.substring(e.selectionStart,o)+(n||"")+e.value.substr(o);return r(e,i,a),e.selectionEnd=o+t.length,e}n.r(t),n.d(t,{update:function(){return r},wrapCursor:function(){return o}})}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={exports:{}};return e[r].call(i.exports,i,i.exports,n),i.exports}n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,{a:t}),t},n.d=function(e,t){for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};(()=>{"use strict";var e=n(460),t=n(973);var r=n(790),o=n(847);function i(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:[],o=(t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],n=2,function(e){if(Array.isArray(e))return e}(t)||function(e,t){var n,r,o=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=o){var i=[],a=!0,s=!1;try{for(o=o.call(e);!(a=(n=o.next()).done)&&(i.push(n.value),!t||i.length!==t);a=!0);}catch(e){s=!0,r=e}finally{try{!a&&null!=o.return&&o.return()}finally{if(s)throw r}}return i}}(t,2)||function(e,t){if(e){if("string"==typeof e)return i(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return i(e,t)}}(t,n)||function(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),a=o[0],s=o[1],c=Function("return "+e.search)(),u=Function("return "+e.replace)(),l=e.template&&Function("return "+e.template)(),f=e.context&&Function("return "+e.context)();return Array.isArray(r)&&r.length&&a&&s&&(c=function(e,t,n){t(r.filter(function(t){return"".concat(t[a]).toLowerCase().includes(e.toLowerCase())}))},u=function(e){return"".concat(e[s])}),{id:e.id,index:e.index,cache:e.cache,match:new RegExp(e.match),search:c,replace:u,template:l,context:f}},s=function(e,t){if(!e.area_label)throw Error("Textcomplete: No label provided.");var n=e.area_label,r=e.stop_enter_propagation||!1;if(!e.strategies||!Array.isArray(e.strategies))throw Error("Textcomplete: No strategies provided.");var o=e.strategies.map(function(e){return a(e,e.data,e.comparatorKeys)});!o.length&&console.warn("Textcomplete: No strategies provided. There will be no autocomplete.");var i={dropdown:Object.assign({},e.dropdown_option)},s="\n :root {\n --background-color: ".concat(t.backgroundColor,";\n --secondary-background-color: ").concat(t.secondaryBackgroundColor,";\n --text-color: ").concat(t.textColor,";\n --primary-color: ").concat(t.primaryColor,";\n };\n ");return{label:n,strategies:o,option:i,stopEnterPropagation:r,css:s}};e.l.events.addEventListener(e.l.RENDER_EVENT,function(n){var o=s(n.detail.args,n.detail.theme),i=o.label,a=o.strategies,c=o.option,u=o.stopEnterPropagation,l=o.css,f=window.parent.document.querySelector('textarea[aria-label="'.concat(i,'"]'));if(f.textcompleteInitialized){console.warn("Textcomplete already initialized for this textarea.");return}var d=document.createElement("style");d.innerHTML=document.querySelector("style").innerHTML+"\n"+l,window.parent.document.head.appendChild(d),c.dropdown.parent=f.parentElement||window.parent.document.querySelector("#root");var h=new r.TextareaEditor(f),p=new t.Textcomplete(h,a,c);f.textcompleteInitialized=!0,f.setAttribute("data-textcomplete",JSON.stringify(n.detail.args.dropdown_option)),u&&f.setAttribute("data-textcomplete-stopenterpropagation",!0),p.on("rendered",function(){f.parentElement.querySelector(".textcomplete-dropdown").style.top="4px"}),p.on("selected",function(e){var t=e.detail.searchResult,n=f.value;delete t.strategy,console.log("Textcomplete selected",t),console.log("Text value",n)}),e.l.setFrameHeight()}),e.l.setComponentReady()})()})(); +(()=>{var e={344:function(e,t,n){"use strict";function r(e,t){for(var n=0;no&&(e.left=o-r),this.el.style.left="".concat(e.left,"px")}else e.right&&(e.right-r<0&&(e.right=0),this.el.style.right="".concat(e.right,"px"));var i=!1,a=this.option.placement||t.DEFAULT_DROPDOWN_PLACEMENT;if("auto"===a){var c=this.items.length*e.lineHeight;i=null!=e.clientTop&&e.clientTop+c>n.clientHeight}"top"===a||i?(this.el.style.bottom="".concat(n.clientHeight-e.top+e.lineHeight,"px"),this.el.style.top="auto"):(this.el.style.top="".concat(e.top,"px"),this.el.style.bottom="auto")}return this}},{key:"getNextActiveIndex",value:function(){if(null==this.activeIndex)throw Error();return this.activeIndex0)||void 0===arguments[0]||arguments[0];return this.completer.destroy(),this.dropdown.destroy(),e&&this.editor.destroy(),this.stopListening(),this}},{key:"isShown",value:function(){return this.dropdown.isShown()}},{key:"hide",value:function(){return this.dropdown.hide(),this}},{key:"trigger",value:function(e){return this.isQueryInFlight?this.nextPendingQuery=e:(this.isQueryInFlight=!0,this.nextPendingQuery=null,this.completer.run(e)),this}},{key:"startListening",value:function(){var e=this;this.editor.on("move",this.handleMove).on("enter",this.handleEnter).on("esc",this.handleEsc).on("change",this.handleChange),this.dropdown.on("select",this.handleSelect);var t=!0,n=!1,r=void 0;try{for(var o,i,a,c=u[Symbol.iterator]();!(t=(a=c.next()).done);t=!0)i=this,function(){var t=a.value;i.dropdown.on(t,function(n){return e.emit(t,n)})}()}catch(e){n=!0,r=e}finally{try{!t&&null!=c.return&&c.return()}finally{if(n)throw r}}this.completer.on("hit",this.handleHit),null===(o=this.dropdown.el.ownerDocument.defaultView)||void 0===o||o.addEventListener("resize",this.handleResize)}},{key:"stopListening",value:function(){var e;null===(e=this.dropdown.el.ownerDocument.defaultView)||void 0===e||e.removeEventListener("resize",this.handleResize),this.completer.removeAllListeners(),this.dropdown.removeAllListeners(),this.editor.removeListener("move",this.handleMove).removeListener("enter",this.handleEnter).removeListener("esc",this.handleEsc).removeListener("change",this.handleChange)}}],r(a.prototype,l),h}(a.EventEmitter);t.Textcomplete=l},973:function(e,t,n){"use strict";var r=this&&this.__createBinding||(Object.create?function(e,t,n,r){void 0===r&&(r=n);var o=Object.getOwnPropertyDescriptor(t,n);(!o||("get"in o?!t.__esModule:o.writable||o.configurable))&&(o={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,r,o)}:function(e,t,n,r){void 0===r&&(r=n),e[r]=t[n]}),o=this&&this.__exportStar||function(e,t){for(var n in e)"default"!==n&&!Object.prototype.hasOwnProperty.call(t,n)&&r(t,e,n)};Object.defineProperty(t,"__esModule",{value:!0}),o(n(344),t),o(n(329),t),o(n(937),t),o(n(363),t),o(n(134),t),o(n(946),t),o(n(125),t)},125:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.createCustomEvent=void 0;var n="undefined"!=typeof window&&!!window.CustomEvent;t.createCustomEvent=function(e,t){if(n)return new CustomEvent(e,t);var r=document.createEvent("CustomEvent");return r.initCustomEvent(e,!1,(null==t?void 0:t.cancelable)||!1,(null==t?void 0:t.detail)||void 0),r}},248:function(e){"use strict";var t=Object.prototype.hasOwnProperty,n="~";function r(){}function o(e,t,n){this.fn=e,this.context=t,this.once=n||!1}function i(e,t,r,i,a){if("function"!=typeof r)throw TypeError("The listener must be a function");var c=new o(r,i||e,a),s=n?n+t:t;return e._events[s]?e._events[s].fn?e._events[s]=[e._events[s],c]:e._events[s].push(c):(e._events[s]=c,e._eventsCount++),e}function a(e,t){0==--e._eventsCount?e._events=new r:delete e._events[t]}function c(){this._events=new r,this._eventsCount=0}Object.create&&(r.prototype=Object.create(null),!new r().__proto__&&(n=!1)),c.prototype.eventNames=function(){var e,r,o=[];if(0===this._eventsCount)return o;for(r in e=this._events)t.call(e,r)&&o.push(n?r.slice(1):r);return Object.getOwnPropertySymbols?o.concat(Object.getOwnPropertySymbols(e)):o},c.prototype.listeners=function(e){var t=n?n+e:e,r=this._events[t];if(!r)return[];if(r.fn)return[r.fn];for(var o=0,i=r.length,a=Array(i);oparseInt(l.height)&&(u.overflowY="scroll"):u.overflow="hidden",s.textContent=e.value.substring(0,o),f&&(s.textContent=s.textContent.replace(/\s/g,"\xa0"));var d=document.createElement("span");d.textContent=e.value.substring(o)||".",s.appendChild(d);var h={top:d.offsetTop+parseInt(l.borderTopWidth),left:d.offsetLeft+parseInt(l.borderLeftWidth),height:parseInt(l.lineHeight)};return a?d.style.backgroundColor="#aaa":document.body.removeChild(s),h}void 0!==e.exports?e.exports=o:n&&(window.getCaretCoordinates=o)}()},714:function(e,t,n){"use strict";function r(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n1&&void 0!==arguments[1]?arguments[1]:[],i=(t=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],n=2,function(e){if(Array.isArray(e))return e}(t)||function(e,t){var n,r,o=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=o){var i=[],a=!0,c=!1;try{for(o=o.call(e);!(a=(n=o.next()).done)&&(i.push(n.value),!t||i.length!==t);a=!0);}catch(e){c=!0,r=e}finally{try{!a&&null!=o.return&&o.return()}finally{if(c)throw r}}return i}}(t,2)||function(e,t){if(e){if("string"==typeof e)return r(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);if("Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return r(e,t)}}(t,n)||function(){throw TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()),a=i[0],c=i[1],s=Function("return "+e.search)(),u=Function("return "+e.replace)(),l=e.template&&Function("return "+e.template)(),f=e.context&&Function("return "+e.context)();return Array.isArray(o)&&o.length&&a&&c&&(s=function(e,t,n){t(o.filter(function(t){return"".concat(t[a]).toLowerCase().includes(e.toLowerCase())}))},u=function(e){return"".concat(e[c])}),{id:e.id,index:e.index,cache:e.cache,match:new RegExp(e.match),search:s,replace:u,template:l,context:f}},i=function(e,t){if(!e.area_label)throw Error("Textcomplete: No label provided.");var n=e.area_label,r=e.stop_enter_propagation||!1;if(!e.strategies||!Array.isArray(e.strategies))throw Error("Textcomplete: No strategies provided.");var i=e.strategies.map(function(e){return o(e,e.data,e.comparatorKeys)});!i.length&&console.warn("Textcomplete: No strategies provided. There will be no autocomplete.");var a={dropdown:Object.assign({},e.dropdown_option)},c="\n :root {\n --background-color: ".concat(t.backgroundColor,";\n --secondary-background-color: ").concat(t.secondaryBackgroundColor,";\n --text-color: ").concat(t.textColor,";\n --primary-color: ").concat(t.primaryColor,";\n };\n ");return{label:n,strategies:i,option:a,stopEnterPropagation:r,css:c}}},460:function(e,t,n){"use strict";function r(e,t){return null!=t&&"undefined"!=typeof Symbol&&t[Symbol.hasInstance]?!!t[Symbol.hasInstance](e):e instanceof t}n.d(t,{l:function(){return c}});var o,i,a=function(){return(a=Object.assign||function(e){for(var t,n=1,r=arguments.length;n0?e.argsDataframeToObject(t.dfs):{};n=a(a({},n),r);var o=!!t.disabled,i=t.theme;i&&s(i);var c={disabled:o,args:n,theme:i},u=new CustomEvent(e.RENDER_EVENT,{detail:c});e.events.dispatchEvent(u)},e.argsDataframeToObject=function(e){return null},e.toArrowTable=function(e){return null},e.sendBackMsg=function(e,t){window.parent.postMessage(a({isStreamlitMessage:!0,type:e},t),"*")},e}(),s=function(e){var t=document.createElement("style");document.head.appendChild(t),t.innerHTML="\n :root {\n --primary-color: ".concat(e.primaryColor,";\n --background-color: ").concat(e.backgroundColor,";\n --secondary-background-color: ").concat(e.secondaryBackgroundColor,";\n --text-color: ").concat(e.textColor,";\n --font: ").concat(e.font,";\n }\n\n body {\n background-color: var(--background-color);\n color: var(--text-color);\n }\n ")}},471:function(e,t,n){"use strict";function r(e,t,n){let r=e.value,o=t+(n||""),i=document.activeElement,a=0,c=0;for(;a=0&&o.length-c-1>=0&&r[r.length-c-1]===o[o.length-c-1];)c++;a=Math.min(a,Math.min(r.length,o.length)-c),e.setSelectionRange(a,r.length-c);let s=o.substring(a,o.length-c);if(e.focus(),!document.execCommand("insertText",!1,s)){e.value=o;let t=document.createEvent("Event");t.initEvent("input",!0,!0),e.dispatchEvent(t)}return e.setSelectionRange(t.length,t.length),i.focus(),e}function o(e,t,n){let o=e.selectionEnd,i=e.value.substr(0,e.selectionStart)+t,a=e.value.substring(e.selectionStart,o)+(n||"")+e.value.substr(o);return r(e,i,a),e.selectionEnd=o+t.length,e}n.r(t),n.d(t,{update:function(){return r},wrapCursor:function(){return o}})}},t={};function n(r){var o=t[r];if(void 0!==o)return o.exports;var i=t[r]={exports:{}};return e[r].call(i.exports,i,i.exports,n),i.exports}n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,{a:t}),t},n.d=function(e,t){for(var r in t)n.o(t,r)&&!n.o(e,r)&&Object.defineProperty(e,r,{enumerable:!0,get:t[r]})},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};(()=>{"use strict";var e=n(460),t=n(973);var r=n(790),o=n(714);e.l.events.addEventListener(e.l.RENDER_EVENT,function(n){var i=(0,o.a)(n.detail.args,n.detail.theme),a=i.label,c=i.strategies,s=i.option,u=i.stopEnterPropagation,l=i.css,f=window.parent.document.querySelector("#root"),d=window.parent.document.querySelector('textarea[aria-label="'.concat(a,'"]'));if(d.textcompleteInitialized){console.warn("Textcomplete already initialized for this textarea.");return}var h=document.createElement("style");h.innerHTML=document.querySelector("style").innerHTML+"\n"+l,window.parent.document.head.appendChild(h),s.dropdown.parent=d.parentElement||f;var p=new r.TextareaEditor(d),v=new t.Textcomplete(p,c,s);d.textcompleteInitialized=!0,d.setAttribute("data-textcomplete",JSON.stringify(n.detail.args.dropdown_option)),u&&d.setAttribute("data-textcomplete-stopenterpropagation",!0),v.on("rendered",function(){d.parentElement.querySelector(".textcomplete-dropdown").style.top="4px"}),v.on("selected",function(e){var t=e.detail.searchResult,n=d.value;delete t.strategy,console.log("Textcomplete selected",t),console.log("Text value",n);var r=new InputEvent("textInput",{data:" ",bubbles:!0,cancelable:!1});Object.defineProperty(r,"target",{writable:!1,value:d}),Object.defineProperty(r,"srcElement",{writable:!1,value:d});var o=new Event("change",{bubbles:!0,cancelable:!1});Object.defineProperty(o,"target",{writable:!1,value:d}),o._reactName="onChange",o.nativeEvent=r,f.dispatchEvent(o),d.dispatchEvent(o)}),e.l.setFrameHeight()}),e.l.setComponentReady()})()})(); //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/jest.config.ts b/textcomplete/frontend/jest.config.ts similarity index 100% rename from jest.config.ts rename to textcomplete/frontend/jest.config.ts diff --git a/textcomplete/frontend/package-lock.json b/textcomplete/frontend/package-lock.json index 6674744..b47d13a 100644 --- a/textcomplete/frontend/package-lock.json +++ b/textcomplete/frontend/package-lock.json @@ -27,6 +27,7 @@ "husky": "^8.0.3", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", + "patch-package": "^8.0.0", "prettier": "3.0.3" }, "engines": { @@ -2390,6 +2391,13 @@ "license": "Apache-2.0", "peer": true }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true, + "license": "BSD-2-Clause" + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -2826,6 +2834,16 @@ "dev": true, "license": "MIT" }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -5225,6 +5243,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-yarn-workspace-root": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", + "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "micromatch": "^4.0.2" + } + }, "node_modules/flat-cache": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", @@ -5318,6 +5346,32 @@ "node": ">= 0.6" } }, + "node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/fs-monkey": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.6.tgz", @@ -7433,6 +7487,25 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz", + "integrity": "sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.5", + "isarray": "^2.0.5", + "jsonify": "^0.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", @@ -7440,6 +7513,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stable-stringify/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -7453,6 +7533,39 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonfile/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/jsonify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", + "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", + "dev": true, + "license": "Public Domain", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7463,6 +7576,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/klaw-sync": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", + "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.1.11" + } + }, "node_modules/kleur": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", @@ -8075,6 +8198,16 @@ "node": ">= 0.8.0" } }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8212,6 +8345,91 @@ "node": ">= 0.8" } }, + "node_modules/patch-package": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", + "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@yarnpkg/lockfile": "^1.1.0", + "chalk": "^4.1.2", + "ci-info": "^3.7.0", + "cross-spawn": "^7.0.3", + "find-yarn-workspace-root": "^2.0.0", + "fs-extra": "^9.0.0", + "json-stable-stringify": "^1.0.2", + "klaw-sync": "^6.0.0", + "minimist": "^1.2.6", + "open": "^7.4.2", + "rimraf": "^2.6.3", + "semver": "^7.5.3", + "slash": "^2.0.0", + "tmp": "^0.0.33", + "yaml": "^2.2.2" + }, + "bin": { + "patch-package": "index.js" + }, + "engines": { + "node": ">=14", + "npm": ">5" + } + }, + "node_modules/patch-package/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/patch-package/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/patch-package/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/patch-package/node_modules/slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9865,6 +10083,19 @@ "dev": true, "license": "MIT" }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -10895,6 +11126,19 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.6.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", diff --git a/textcomplete/frontend/package.json b/textcomplete/frontend/package.json index 38225eb..055a2fb 100644 --- a/textcomplete/frontend/package.json +++ b/textcomplete/frontend/package.json @@ -4,6 +4,7 @@ "description": "Streamlit autocomplete Textcomplete editor for HTMLTextAreaElement", "main": "index.js", "scripts": { + "postinstall": "patch-package", "rspack": "rspack", "build": "rspack build", "dev": "rspack dev", @@ -35,6 +36,7 @@ "husky": "^8.0.3", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", + "patch-package": "^8.0.0", "prettier": "3.0.3" }, "overrides": { diff --git a/textcomplete/frontend/patches/@textcomplete+textarea+0.1.13.patch b/textcomplete/frontend/patches/@textcomplete+textarea+0.1.13.patch new file mode 100644 index 0000000..500d410 --- /dev/null +++ b/textcomplete/frontend/patches/@textcomplete+textarea+0.1.13.patch @@ -0,0 +1,14 @@ +diff --git a/node_modules/@textcomplete/textarea/dist/TextareaEditor.js b/node_modules/@textcomplete/textarea/dist/TextareaEditor.js +index c2ed775..461197e 100644 +--- a/node_modules/@textcomplete/textarea/dist/TextareaEditor.js ++++ b/node_modules/@textcomplete/textarea/dist/TextareaEditor.js +@@ -23,6 +23,9 @@ class TextareaEditor extends core_1.Editor { + } + else if (code === "ENTER") { + event = this.emitEnterEvent(); ++ if (el.dataset['textcompleteStopenterpropagation'] === 'true') { ++ e.stopImmediatePropagation() ++ } + } + else if (code === "ESC") { + event = this.emitEscEvent(); diff --git a/textcomplete/frontend/project.json b/textcomplete/frontend/project.json deleted file mode 100644 index 546ad88..0000000 --- a/textcomplete/frontend/project.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "name": "streamlit-textcomplete-frontend", - "$schema": "../../../../node_modules/nx/schemas/project-schema.json", - "sourceRoot": "packages/streamlit-textcomplete/frontend", - "projectType": "application", - "targets": {}, - "tags": [] -} diff --git a/textcomplete/frontend/src/helpers.js b/textcomplete/frontend/src/helpers.js new file mode 100644 index 0000000..dce3ea3 --- /dev/null +++ b/textcomplete/frontend/src/helpers.js @@ -0,0 +1,76 @@ +/** + * Convert stringified functions back into functions + * @param {import('@textcomplete/core').StrategyProps} props + * @param {any[]} data + * @param {string} key + */ +export const convertStrategyProps = (props, data = [], [labelKey, valueKey] = []) => { + let searchFn = new Function('return ' + props.search)(); + let replaceFn = new Function('return ' + props.replace)(); + let templateFn = props.template && new Function('return ' + props.template)(); + let contextFn = props.context && new Function('return ' + props.context)(); + // If data is provided, create a default search function that filters the data by key + if (Array.isArray(data) && data.length && labelKey && valueKey) { + // (Required) When the current input matches the "match" regexp above, this + // function is called. The first argument is the captured substring. + // You can callback only once for each search. + searchFn = (term, callback, match) => { + const filteredData = data.filter(item => + `${item[labelKey]}`.toLowerCase().includes(term.toLowerCase()) + ); + callback(filteredData); + }; + // (Required) Specify how to update the editor value. The whole substring + // matched in the match phase will be replaced by the returned value. + // Note that it can return a string or an array of two strings. If it returns + // an array, the matched substring will be replaced by the concatenated string + // and the cursor will be set between first and second strings. + replaceFn = item => `${item[valueKey]}`; + } + return { + id: props.id, + index: props.index, + cache: props.cache, + match: new RegExp(props.match), + search: searchFn, + replace: replaceFn, + template: templateFn, + context: contextFn, + }; +}; + +/** + * Parse the Textcomplete args + * @param {any} args + * @param {any} theme + * */ +// @returns {import('@textcomplete/core').TextcompleteOption} +export const parseTextcompleteArgs = (args, theme) => { + if (!args.area_label) { + throw new Error('Textcomplete: No label provided.'); + } + const label = args.area_label; + const stopEnterPropagation = args.stop_enter_propagation || false; + if (!args.strategies || !Array.isArray(args.strategies)) { + throw new Error('Textcomplete: No strategies provided.'); + } + const strategies = args.strategies.map(s => + convertStrategyProps(s, s.data, s.comparatorKeys) + ); + if (!strategies.length) { + console.warn('Textcomplete: No strategies provided. There will be no autocomplete.'); + } + const option = { + dropdown: Object.assign({}, args.dropdown_option), + }; + const variables = ` + :root { + --background-color: ${theme.backgroundColor}; + --secondary-background-color: ${theme.secondaryBackgroundColor}; + --text-color: ${theme.textColor}; + --primary-color: ${theme.primaryColor}; + }; + `; + const css = variables; + return { label, strategies, option, stopEnterPropagation, css }; +}; diff --git a/textcomplete/frontend/src/index.js b/textcomplete/frontend/src/index.js index 8b297f0..99039ec 100644 --- a/textcomplete/frontend/src/index.js +++ b/textcomplete/frontend/src/index.js @@ -2,7 +2,7 @@ import { Streamlit } from './streamlit'; import { Textcomplete } from '@textcomplete/core'; import { TextareaEditor } from '@textcomplete/textarea'; -import {} from '@textcomplete/utils'; +import { parseTextcompleteArgs } from './helpers'; /** * Event handler for textcomplete event @@ -11,83 +11,7 @@ import {} from '@textcomplete/utils'; * @param {Object} e.detail - The detail of the event. * @param {import('@textcomplete/core').SearchResult} e.detail.searchResult - The search result. */ - -/** - * Convert stringified functions back into functions - * @param {import('@textcomplete/core').StrategyProps} props - * @param {any[]} data - * @param {string} key - */ -const convertStrategyProps = (props, data = [], [labelKey, valueKey] = []) => { - let searchFn = new Function('return ' + props.search)(); - let replaceFn = new Function('return ' + props.replace)(); - let templateFn = props.template && new Function('return ' + props.template)(); - let contextFn = props.context && new Function('return ' + props.context)(); - // If data is provided, create a default search function that filters the data by key - if (Array.isArray(data) && data.length && labelKey && valueKey) { - // (Required) When the current input matches the "match" regexp above, this - // function is called. The first argument is the captured substring. - // You can callback only once for each search. - searchFn = (term, callback, match) => { - const filteredData = data.filter(item => - `${item[labelKey]}`.toLowerCase().includes(term.toLowerCase()) - ); - callback(filteredData); - }; - // (Required) Specify how to update the editor value. The whole substring - // matched in the match phase will be replaced by the returned value. - // Note that it can return a string or an array of two strings. If it returns - // an array, the matched substring will be replaced by the concatenated string - // and the cursor will be set between first and second strings. - replaceFn = item => `${item[valueKey]}`; - } - return { - id: props.id, - index: props.index, - cache: props.cache, - match: new RegExp(props.match), - search: searchFn, - replace: replaceFn, - template: templateFn, - context: contextFn, - }; -}; - -/** - * Parse the Textcomplete args - * @param {any} args - * @param {any} theme - * */ -// @returns {import('@textcomplete/core').TextcompleteOption} -const parseTextcompleteArgs = (args, theme) => { - if (!args.area_label) { - throw new Error('Textcomplete: No label provided.'); - } - const label = args.area_label; - const stopEnterPropagation = args.stop_enter_propagation || false; - if (!args.strategies || !Array.isArray(args.strategies)) { - throw new Error('Textcomplete: No strategies provided.'); - } - const strategies = args.strategies.map(s => - convertStrategyProps(s, s.data, s.comparatorKeys) - ); - if (!strategies.length) { - console.warn('Textcomplete: No strategies provided. There will be no autocomplete.'); - } - const option = { - dropdown: Object.assign({}, args.dropdown_option), - }; - const variables = ` - :root { - --background-color: ${theme.backgroundColor}; - --secondary-background-color: ${theme.secondaryBackgroundColor}; - --text-color: ${theme.textColor}; - --primary-color: ${theme.primaryColor}; - }; - `; - const css = variables; - return { label, strategies, option, stopEnterPropagation, css }; -}; +// ----------------------------------------------------------------------------- /** * The component's render function. This will be called immediately after @@ -102,7 +26,7 @@ function onRender(event) { event.detail.args, event.detail.theme ); - + const rootElement = window.parent.document.querySelector('#root'); const textareaElement = window.parent.document.querySelector( `textarea[aria-label="${label}"]` ); @@ -118,9 +42,7 @@ function onRender(event) { style.innerHTML = document.querySelector('style').innerHTML + '\n' + css; window.parent.document.head.appendChild(style); - // const parent = findParentByTestId(textareaElement, 'element-container'); - option.dropdown.parent = - textareaElement.parentElement || window.parent.document.querySelector('#root'); + option.dropdown.parent = textareaElement.parentElement || rootElement; const editor = new TextareaEditor(textareaElement); const textcomplete = new Textcomplete(editor, strategies, option); @@ -152,9 +74,31 @@ function onRender(event) { textcomplete.on('selected', e => { const { searchResult } = e.detail; const text = textareaElement.value; + // textareaElement.value += ' '; delete searchResult.strategy; console.log('Textcomplete selected', searchResult); console.log('Text value', text); + + // Create a new InputEvent object with the same properties and methods as the native event object + const nativeEvent = new InputEvent('textInput', { + data: ' ', + bubbles: true, + cancelable: false, + }); + Object.defineProperty(nativeEvent, 'target', { writable: false, value: textareaElement }); + Object.defineProperty(nativeEvent, 'srcElement', { writable: false, value: textareaElement }); + // Create a new synthetic event object with the same properties and methods as the synthetic event object that is created by React + const changeEvent = new Event('change', { + bubbles: true, + cancelable: false, + }); + Object.defineProperty(changeEvent, 'target', { writable: false, value: textareaElement }); + // Attach the synthetic event object to the native event object using the _reactName property + changeEvent._reactName = 'onChange'; + changeEvent.nativeEvent = nativeEvent; + // Dispatch the native event object on the textarea element + rootElement.dispatchEvent(changeEvent); + textareaElement.dispatchEvent(changeEvent) // Streamlit.setComponentValue({ searchResult, text }); // FIXME: updating component causes re-render and resets textarea value by original react component state });