From 8e2fa18178b980b15913ab6cce72596617caa177 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Jul 2026 10:01:57 +0000 Subject: [PATCH 1/2] docs: initial scan OKF documentation Generate an Open Knowledge Format (OKF v0.1) documentation bundle under docs/okf/ covering tagui.py's public API and process lifecycle, the rpa package re-export, and the packaging/sample scripts. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_011MR7MDaEK9Dpa2t1rL4b5T --- docs/okf/index.md | 48 +++++++++++ docs/okf/log.md | 8 ++ docs/okf/rpa-package/index.md | 10 +++ docs/okf/rpa-package/rpa.md | 50 +++++++++++ docs/okf/rpa-package/setup.md | 40 +++++++++ docs/okf/sample.md | 56 +++++++++++++ docs/okf/setup.md | 36 ++++++++ docs/okf/tagui.md | 152 ++++++++++++++++++++++++++++++++++ docs/okf/tagui/close.md | 52 ++++++++++++ docs/okf/tagui/download.md | 53 ++++++++++++ docs/okf/tagui/index.md | 21 +++++ docs/okf/tagui/init.md | 65 +++++++++++++++ docs/okf/tagui/pack.md | 55 ++++++++++++ docs/okf/tagui/send.md | 55 ++++++++++++ docs/okf/tagui/setup.md | 57 +++++++++++++ docs/okf/tagui/update.md | 56 +++++++++++++ 16 files changed, 814 insertions(+) create mode 100644 docs/okf/index.md create mode 100644 docs/okf/log.md create mode 100644 docs/okf/rpa-package/index.md create mode 100644 docs/okf/rpa-package/rpa.md create mode 100644 docs/okf/rpa-package/setup.md create mode 100644 docs/okf/sample.md create mode 100644 docs/okf/setup.md create mode 100644 docs/okf/tagui.md create mode 100644 docs/okf/tagui/close.md create mode 100644 docs/okf/tagui/download.md create mode 100644 docs/okf/tagui/index.md create mode 100644 docs/okf/tagui/init.md create mode 100644 docs/okf/tagui/pack.md create mode 100644 docs/okf/tagui/send.md create mode 100644 docs/okf/tagui/setup.md create mode 100644 docs/okf/tagui/update.md diff --git a/docs/okf/index.md b/docs/okf/index.md new file mode 100644 index 0000000..e2ecab2 --- /dev/null +++ b/docs/okf/index.md @@ -0,0 +1,48 @@ +--- +okf_version: "0.1" +source_repo: marcelocecin/RPA-Python +source_commit: 8259b4ca1005a79523e672c1c833accd84fccb76 +generated_by: okf-repo-docs skill +--- + +# RPA for Python — OKF Documentation + +RPA for Python is a Python wrapper around [TagUI](https://github.com/tebelorg/Tump), +an open-source RPA (robotic process automation) tool. It exposes website +automation, computer-vision automation, OCR, and keyboard/mouse automation +through a single flat function-based API (`import rpa as r`). The wrapper +manages a TagUI subprocess in "live mode": every call from Python is sent as +one instruction over the subprocess's stdin and the reply is read back from +a temp output file or stdout. + +## Modules + +* [tagui](tagui.md) - the wrapper module: process lifecycle, TagUI + installation/update, and the full public automation API. + +## Key functions + +* [tagui/setup](tagui/setup.md) - downloads and installs TagUI for the + current OS. +* [tagui/init](tagui/init.md) - starts the TagUI subprocess and waits for + it to become ready. +* [tagui/send](tagui/send.md) - sends one instruction to the running TagUI + process and waits for it to finish. +* [tagui/close](tagui/close.md) - terminates the TagUI subprocess and + cleans up generated files. +* [tagui/pack](tagui/pack.md) - bundles a TagUI installation for offline + ("air-gapped") deployment. +* [tagui/update](tagui/update.md) - builds a self-extracting update script + for an offline deployment. +* [tagui/download](tagui/download.md) - Python 2/3-compatible URL-to-file + download helper used throughout the module. + +## Packaging + +* [rpa-package](rpa-package/) - the distributable `rpa` PyPI package + (`pip install rpa`), a thin re-export of `tagui.py` plus its own + `setup.py`. +* [setup](setup.md) - root `setup.py`, packages this repo as the `tagui` + PyPI distribution. +* [sample](sample.md) - `sample.py`, a runnable usage example exercising + the public API end to end. diff --git a/docs/okf/log.md b/docs/okf/log.md new file mode 100644 index 0000000..0f9e3c5 --- /dev/null +++ b/docs/okf/log.md @@ -0,0 +1,8 @@ +# Directory Update Log + +## 2026-07-22 +- **Initial scan**: Generated the OKF bundle for `marcelocecin/RPA-Python` + at commit `8259b4c`. Documented the `tagui` module (1 Module concept, 7 + Function concepts for entry points with non-trivial logic), the `rpa` + distributable package, and the two `setup.py` build scripts plus + `sample.py`. diff --git a/docs/okf/rpa-package/index.md b/docs/okf/rpa-package/index.md new file mode 100644 index 0000000..a7df633 --- /dev/null +++ b/docs/okf/rpa-package/index.md @@ -0,0 +1,10 @@ +# rpa-package + +Concepts for `rpa_package/`, the source of the `rpa` PyPI distribution +(the package name used in this project's own documentation and samples, +`import rpa as r`). + +* [rpa](rpa.md) - re-exports `tagui.py`'s public API under the `rpa` + module name. +* [setup](setup.md) - `setuptools` packaging script for the `rpa` + distribution. diff --git a/docs/okf/rpa-package/rpa.md b/docs/okf/rpa-package/rpa.md new file mode 100644 index 0000000..7a3febb --- /dev/null +++ b/docs/okf/rpa-package/rpa.md @@ -0,0 +1,50 @@ +--- +type: Module +title: rpa_package/rpa +description: The rpa PyPI package's module — a one-line re-export of tagui.py's entire public API for backward compatibility. +resource: rpa_package/rpa.py +tags: [rpa, tagui, packaging, backward-compatibility] +timestamp: 2026-07-22T09:58:59Z +--- + +# rpa_package/rpa + +# Responsibility + +Lets users write `import rpa as r` (the package's advertised usage, see +[sample](../sample.md)) instead of `import tagui`. The file is generated +by [`tagui.pack()`](../tagui/pack.md) as a copy of the root `tagui.py`, +then re-exports everything from it with `from tagui import *` so the two +distributions (`tagui` and `rpa` on PyPI) stay behaviorally identical. + +# Public Interface + +```python +from tagui import * +``` + +Re-exports the entire public interface documented in +[tagui](../tagui.md) (module and per-function concepts under +[tagui/](../tagui/)). + +# Dependencies + +- [tagui](../tagui.md) — re-exports all of its public symbols. + +# Used By + +- [rpa-package/setup](setup.md) — packages this file as the `rpa` PyPI + distribution (`py_modules=['rpa'], install_requires=['tagui>=1.50.0']`). + +# Usage Example + +```python +import rpa as r +r.init() +``` + +# Notes + +- Kept in sync with `tagui.py` by [`pack()`](../tagui/pack.md) + (`shutil.copyfile(.../tagui.py, 'rpa.py')`) rather than maintained + independently — do not hand-edit without also updating `tagui.py`. diff --git a/docs/okf/rpa-package/setup.md b/docs/okf/rpa-package/setup.md new file mode 100644 index 0000000..6c5ddc8 --- /dev/null +++ b/docs/okf/rpa-package/setup.md @@ -0,0 +1,40 @@ +--- +type: Script +title: rpa_package/setup.py +description: setuptools packaging script that builds and publishes the rpa PyPI distribution. +resource: rpa_package/setup.py +tags: [packaging, setuptools, pypi] +timestamp: 2026-07-22T09:58:59Z +--- + +# rpa_package/setup.py + +# Responsibility + +Standard `setuptools.setup()` invocation that defines the `rpa` PyPI +package: ships `rpa.py` as its single module, declares a runtime +dependency on `tagui>=1.50.0`, and carries the package metadata +(author, license, classifiers, long description) shown on PyPI. + +# Public Interface + +```python +setup(name='rpa', version='1.50.0', py_modules=['rpa'], + install_requires=['tagui>=1.50.0'], ...) +``` + +# Dependencies + +- [rpa-package/rpa](rpa.md) — the module this script packages. +- Declares an `install_requires` dependency on the separately-published + `tagui` package (see [setup](../setup.md)). + +# Used By + +Standalone build entry point (`python setup.py sdist`/`pip install .`), +not imported by other code. + +# Notes + +- Kept in lockstep with the root [`setup.py`](../setup.md) and with + `tagui.py`'s own `__version__` — all three currently pin `1.50.0`. diff --git a/docs/okf/sample.md b/docs/okf/sample.md new file mode 100644 index 0000000..02b4a85 --- /dev/null +++ b/docs/okf/sample.md @@ -0,0 +1,56 @@ +--- +type: Script +title: sample.py +description: Runnable usage example that searches Yahoo, takes a screenshot, and visits DuckDuckGo, demonstrating the core public API end to end. +resource: sample.py +tags: [example, rpa, tagui] +timestamp: 2026-07-22T09:58:59Z +--- + +# sample.py + +# Responsibility + +The canonical "getting started" example for the package (mirrored in the +project README). Demonstrates the typical call sequence — `init()`, +`url()`, `type()`, `read()`, `click()`, `wait()`, `snap()`, `close()` — and +documents, in comments, the different forms a UI element identifier can +take (XPath/CSS selector, DOM attribute, `.png`/`.bmp` visual identifier, +OCR fallback, x/y coordinates). + +# Public Interface + +Not an importable module — a standalone script run directly +(`python sample.py`). + +# Dependencies + +- [rpa-package/rpa](rpa-package/rpa.md) — imported as `import rpa as r`; + exercises `init`, `url`, `type`, `read`, `click`, `wait`, `snap`, + `close` from [tagui](tagui.md). + +# Used By + +Not imported elsewhere — a standalone runnable example. + +# Usage Example + +```python +import rpa as r +r.init() +r.url('https://ca.yahoo.com') +r.type('ybar-sbq', 'github') +search_text = r.read('ybar-sbq') +r.click('ybar-search') +r.wait(6.6) +r.snap('page', 'results.png') +r.close() +``` + +# Notes + +- The trailing comments in this file are the primary in-repo reference for + the different identifier syntaxes accepted by `click()`/`type()`/ + `read()`/`snap()` and friends (XPath/CSS/attribute selectors, `.png`/ + `.bmp` visual matches with OCR fallback, transparent-background images, + and `x, y` coordinates). diff --git a/docs/okf/setup.md b/docs/okf/setup.md new file mode 100644 index 0000000..6e9d9d0 --- /dev/null +++ b/docs/okf/setup.md @@ -0,0 +1,36 @@ +--- +type: Script +title: setup.py +description: setuptools packaging script that builds and publishes the tagui PyPI distribution. +resource: setup.py +tags: [packaging, setuptools, pypi] +timestamp: 2026-07-22T09:58:59Z +--- + +# setup.py + +# Responsibility + +Standard `setuptools.setup()` invocation that defines the `tagui` PyPI +package: ships `tagui.py` as its single module, and carries the package +metadata (author, license, classifiers, long description) shown on PyPI. + +# Public Interface + +```python +setup(name='tagui', version='1.50.0', py_modules=['tagui'], ...) +``` + +# Dependencies + +- [tagui](tagui.md) — the module this script packages. + +# Used By + +Standalone build entry point (`python setup.py sdist`/`pip install .`), +not imported by other code. + +# Notes + +- Kept in lockstep with [`rpa_package/setup.py`](rpa-package/setup.md) and + with `tagui.py`'s own `__version__` — all three currently pin `1.50.0`. diff --git a/docs/okf/tagui.md b/docs/okf/tagui.md new file mode 100644 index 0000000..7ebff53 --- /dev/null +++ b/docs/okf/tagui.md @@ -0,0 +1,152 @@ +--- +type: Module +title: tagui +description: Python wrapper module that drives a TagUI subprocess in "live mode" to provide RPA for Python's public automation API. +resource: tagui.py +tags: [rpa, tagui, automation, python2-3-compat] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui + +# Responsibility + +`tagui.py` is the entire implementation of the `rpa`/`tagui` PyPI package. +It launches and manages a [TagUI](https://github.com/tebelorg/Tump) +subprocess in "live mode" (`init()`/`close()`), and exposes every RPA +capability (web/desktop automation, computer vision, OCR, keyboard/mouse +control, file I/O) as a flat set of module-level functions that translate +into TagUI instructions sent over the subprocess's stdin +([`send`](tagui/send.md)). It also contains TagUI's own installation, +update, and offline-packaging logic ([`setup`](tagui/setup.md), +[`update`](tagui/update.md), [`pack`](tagui/pack.md)), and Python 2/3 +string/byte compatibility shims (`_py23_*` helpers) since the module +supports both. + +`rpa_package/rpa.py` (see [rpa-package/rpa](rpa-package/rpa.md)) is an +identical copy of this file distributed as the `rpa` package name; `pack()` +regenerates it from `tagui.py` on every run. + +# Public Interface + +Process lifecycle and setup (see individual concepts for the ones with +non-trivial logic): + +```python +setup() # tagui/setup.md +init(visual_automation=False, chrome_browser=True, + headless_mode=False, turbo_mode=False) # tagui/init.md +send(tagui_instruction=None) # tagui/send.md +close() # tagui/close.md +pack() # tagui/pack.md +update() # tagui/update.md +download(download_url=None, filename_to_save=None) # tagui/download.md +``` + +Configuration / diagnostics: + +```python +debug(on_off=None) # get/set debug mode (echoes TagUI output to stdout) +error(on_off=None) # get/set whether errors raise Exception instead of just printing +show_error(error_message=None) # print or raise the given error message, per error() mode +tagui_location(location=None) # get/set the folder TagUI is installed to (default: user home) +timeout(timeout_in_seconds=None) # get/set the default wait timeout (seconds) for UI elements +download_location(location=None) # get/set the browser's file download directory +coord(x_coordinate=0, y_coordinate=0) # build an "(x,y)" coordinate string accepted by other calls +``` + +Web / desktop UI interaction (each waits for readiness via `_started()`/ +`exist()` then delegates to `send()`): + +```python +url(webpage_url=None) # navigate, or return current URL +exist(element_identifier=None) # True if element/coordinate exists (waits up to timeout) +present(element_identifier=None) # True if element/coordinate is present now (no wait) +click(element_identifier=None, test_coordinate=None) +rclick(element_identifier=None, test_coordinate=None) # right-click +dclick(element_identifier=None, test_coordinate=None) # double-click +hover(element_identifier=None, test_coordinate=None) +type(element_identifier=None, text=None, test_coordinate=None) +select(element_identifier=None, option_value=None, test_coordinate=None) +read(element_identifier=None, test_coordinate=None) +snap(element_identifier=None, filename_to_save=None, test_coordinate=None) +table(element_identifier=None, filename_to_save=None) # export an HTML table to CSV +upload(element_identifier=None, filename_to_upload=None) +frame(main_frame=None, sub_frame=None) # switch webpage context into an iframe +popup(string_in_url=None) # switch webpage context into a popup/tab +count(element_identifier=None) +title() +text() +dom(statement_to_run=None) # run and return an arbitrary JS/DOM statement (chrome mode) +api(url_to_query=None) # stub; recommends using the `requests` package instead +``` + +Keyboard / mouse / vision (require `init(visual_automation=True)`): + +```python +keyboard(keys_and_modifiers=None) +mouse(mouse_action=None) # 'down' or 'up' +vision(command_to_run=None) +mouse_xy() / mouse_x() / mouse_y() +clipboard(text_to_put=None) # get/set OS clipboard +``` + +Misc utilities: + +```python +wait(delay_in_seconds=5.0) +check(condition_to_check=None, text_if_true='', text_if_false='') +ask(text_to_prompt='') # JS prompt() in chrome mode, console input otherwise +focus(app_to_focus=None) # bring a desktop app window to the foreground (Windows/macOS only) +run(command_to_run=None) # run a shell command, return its output +timer() # elapsed seconds of current TagUI flow +telegram(telegram_id=None, text_to_send=None, custom_endpoint=None) # deprecated, see Notes +bin(file_to_bin=None, password=None, server='https://tebel.org/bin/') # deprecated, see Notes +unzip(file_to_unzip=None, unzip_location=None) +load(filename_to_load=None) +echo(text_to_echo='') +dump(text_to_dump=None, filename_to_save=None) # overwrite file with text +write(text_to_write=None, filename_to_save=None) # append text to file +get_text(source_text=None, left=None, right=None, count=1) # substring between two delimiters +del_chars(source_text=None, characters=None) # strip given characters from a string +``` + +# Dependencies + +None outside the standard library — imports only `subprocess`, `os`, +`sys`, `time`, `platform` (plus `zipfile`, `shutil`, `base64`, `urllib` +locally inside specific functions). + +# Used By + +- [rpa-package/rpa](rpa-package/rpa.md) — re-exports everything from this + module (`from tagui import *`) under the `rpa` package name. +- [sample](sample.md) — exercises the public API (`init`, `url`, `type`, + `read`, `click`, `wait`, `snap`, `close`). +- [setup](setup.md) — packages this file as the `tagui` PyPI distribution + (`py_modules=['tagui']`). + +# Usage Example + +```python +import rpa as r +r.init() +r.url('https://ca.yahoo.com') +r.type('ybar-sbq', 'github') +r.click('ybar-search') +r.snap('page', 'results.png') +r.close() +``` + +# Notes + +- Supports both Python 2 and Python 3 via the `_python2_env()`/ + `_python3_env()`/`_py23_*` helpers — string/byte handling is duplicated + throughout for this reason. +- `telegram()` and `bin()` are marked deprecated in the project README + (rely on a third-party `tebel.org` relay service); kept for backward + compatibility but not recommended for new code. +- Nearly every function first checks `_started()` (must call `init()` + first) and, for visual/chrome-only calls, `_visual()`/`_chrome()` before + delegating to [`send()`](tagui/send.md); this repeated guard is the + module's main structural pattern. diff --git a/docs/okf/tagui/close.md b/docs/okf/tagui/close.md new file mode 100644 index 0000000..842c5fe --- /dev/null +++ b/docs/okf/tagui/close.md @@ -0,0 +1,52 @@ +--- +type: Function +title: tagui.close +description: Sends the 'done' instruction to terminate the TagUI live-mode subprocess and removes generated flow/log/temp files. +resource: tagui.py#L882 +tags: [rpa, tagui, process-lifecycle] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.close + +# Responsibility + +The counterpart to [`init()`](init.md): tells TagUI to quit (`done` +instruction), waits for the subprocess to exit, then deletes the +generated `rpa_python` flow file, `rpa_python.js`, `rpa_python.raw`, and +`tagui_local.js` (from both the current directory and the directory +`init()` was originally called from, to handle scripts that `chdir()` in +between). Also removes `rpa_python.log`/`rpa_python.txt` unless +`debug()` mode is on. + +# Public Interface + +```python +close() # returns True/False +``` + +# Dependencies + +- Uses `_tagui_write()` and `debug()` from [tagui](../tagui.md). + +# Used By + +- [sample](../sample.md) — calls `r.close()` at the end of the script. +- [tagui.pack](pack.md) — closes the temporary `init()` session it opens + internally before zipping the TagUI installation. + +# Usage Example + +```python +import rpa as r +r.init() +# ... automation steps ... +r.close() +``` + +# Notes + +- Errors via `show_error()` if `init()` was never called, or if the TagUI + process had already died unexpectedly (`_process.poll()` not None). +- Safe to call defensively — the module docs/README recommend "if you + forget to close, just close() next time." diff --git a/docs/okf/tagui/download.md b/docs/okf/tagui/download.md new file mode 100644 index 0000000..7fbd3b0 --- /dev/null +++ b/docs/okf/tagui/download.md @@ -0,0 +1,53 @@ +--- +type: Function +title: tagui.download +description: Python 2/3-compatible helper that downloads a file from a URL to a local path, used throughout the module for fetching TagUI assets. +resource: tagui.py#L1498 +tags: [rpa, tagui, networking] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.download + +# Responsibility + +Shared low-level download primitive. Wraps `urllib.urlretrieve` (Python 2) +or `urllib.request.urlretrieve` (Python 3) behind one signature, defaults +the save filename to the URL's last path segment, deletes any +pre-existing file at the destination first, and reports success purely by +checking the file exists afterward. + +# Public Interface + +```python +download(download_url=None, filename_to_save=None) # returns True/False +``` + +# Dependencies + +None beyond the standard library (`urllib`/`urllib.request`, +`os`) and `_python2_env()` from [tagui](../tagui.md). + +# Used By + +- [tagui.setup](setup.md) — downloads the TagUI zip and (on macOS/Windows) + patch dependencies (PhantomJS, `vcredist_x86.exe`). +- [tagui.pack](pack.md) — downloads the SikuliX Jython jar and the + Windows Visual C++ Redistributable. +- [tagui.update](update.md) — downloads the latest `tagui.py` and each + TagUI delta file. +- `focus()` — downloads `sendKeys.bat` on Windows if not already present. + +# Usage Example + +```python +# internal usage pattern: +download('https://github.com/tebelorg/Tump/releases/download/v1.0.0/TagUI_Linux.zip', + home_directory + '/TagUI_Linux.zip') +``` + +# Notes + +- Swallows the underlying exception and converts any failure (bad URL, no + internet, no content) into a `False` return plus a printed error via + `show_error()`, rather than propagating the original exception. diff --git a/docs/okf/tagui/index.md b/docs/okf/tagui/index.md new file mode 100644 index 0000000..a1abd7f --- /dev/null +++ b/docs/okf/tagui/index.md @@ -0,0 +1,21 @@ +# tagui — Key Functions + +Function-level concepts for the entry points in [tagui](../tagui.md) that +have non-trivial logic (process lifecycle, installation, offline +packaging). The rest of the module's public functions are thin one-line +wrappers around [`send()`](send.md) and are catalogued in the module's own +Public Interface table rather than documented individually. + +* [setup](setup.md) - downloads and installs TagUI for the current OS. +* [init](init.md) - starts the TagUI subprocess and waits for it to become + ready. +* [send](send.md) - sends one instruction to the running TagUI process and + waits for it to finish. +* [close](close.md) - terminates the TagUI subprocess and cleans up + generated files. +* [pack](pack.md) - bundles a TagUI installation for offline ("air-gapped") + deployment. +* [update](update.md) - builds a self-extracting update script for an + offline deployment. +* [download](download.md) - Python 2/3-compatible URL-to-file download + helper used throughout the module. diff --git a/docs/okf/tagui/init.md b/docs/okf/tagui/init.md new file mode 100644 index 0000000..25236c9 --- /dev/null +++ b/docs/okf/tagui/init.md @@ -0,0 +1,65 @@ +--- +type: Function +title: tagui.init +description: Starts (or installs then starts) the TagUI subprocess in live mode and blocks until it is ready to receive instructions. +resource: tagui.py#L471 +tags: [rpa, tagui, process-lifecycle] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.init + +# Responsibility + +Entry point every automation script must call before any UI-interaction +function. Ensures TagUI is installed (calling [`setup()`](setup.md) if +not), writes a "flow" file selecting visual vs. non-visual automation, +launches the TagUI executable via `subprocess.Popen`, and busy-waits on +its stdout until it prints the live-mode ready marker, at which point it +flips `_tagui_started`/`_tagui_visual`/`_tagui_chrome` module state to +True so other functions will proceed. + +# Public Interface + +```python +init(visual_automation=False, chrome_browser=True, + headless_mode=False, turbo_mode=False) # returns True/False +``` + +# Dependencies + +- [tagui.setup](setup.md) — invoked if the TagUI executable isn't present + yet. +- Uses `_tagui_delta()`, `_patch_macos_pjs()`, `_patch_macos_py3()`, + `_python_flow()`/`_visual_flow()`, `_tagui_local()`, `_tagui_read()`/ + `_tagui_write()`, and `_ready()` from [tagui](../tagui.md). + +# Used By + +- Every UI-interaction function in [tagui](../tagui.md) checks + `_started()` and errors if `init()` hasn't been called. +- [tagui.pack](pack.md) — calls `init(False, False)` internally to force a + first-run TagUI sync before zipping. +- [sample](../sample.md) — calls `r.init()` first thing. + +# Usage Example + +```python +import rpa as r +r.init() # default: no visual automation, chrome browser on +r.init(visual_automation=True) # enables keyboard()/mouse()/vision()/clipboard() +r.init(chrome_browser=False) # no browser, e.g. for desktop-only automation +``` + +# Notes + +- `visual_automation=True` additionally requires a working 64-bit + OpenJDK/Java on the machine (checked via `java -version`); `init()` + prints install guidance and returns False if missing. +- `turbo_mode` patches TagUI's own `tagui_chrome.php`/`tagui_header.js`/ + `tagui.sikuli/tagui.py` files in place to shrink scan/sleep intervals — + calling `init()` again with a different `turbo_mode` value toggles the + same patched files back and forth. +- Raises via [`show_error()`](../tagui.md) (print or exception, per + `error()` mode) if called again without an intervening + [`close()`](close.md). diff --git a/docs/okf/tagui/pack.md b/docs/okf/tagui/pack.md new file mode 100644 index 0000000..7d2ecbb --- /dev/null +++ b/docs/okf/tagui/pack.md @@ -0,0 +1,55 @@ +--- +type: Function +title: tagui.pack +description: Bundles the local TagUI installation and this package's own source into rpa_python.zip / rpa.py for offline ("air-gapped") deployment. +resource: tagui.py#L643 +tags: [rpa, tagui, offline-deployment] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.pack + +# Responsibility + +Prepares the two files an air-gapped target machine needs to install RPA +for Python without internet access: `rpa_python.zip` (a full TagUI +installation, including the SikuliX/Jython dependency needed for visual +automation) and a copy of `tagui.py` renamed to `rpa.py`. Run this on a +machine with internet access, then copy both files to the offline target +and follow up with [`setup()`](setup.md) there (triggered automatically by +[`init()`](init.md) when it detects `rpa_python.zip` next to it). + +# Public Interface + +```python +pack() # no arguments; returns True/False +``` + +# Dependencies + +- [tagui.init](init.md) / [tagui.close](close.md) — pack() forces a + `init(False, False)` + `close()` cycle first to guarantee TagUI is + installed and its delta files are synced before zipping. +- [tagui.download](download.md) — fetches the SikuliX Jython jar (and, on + Windows, the Visual C++ Redistributable) into the installation before + zipping. + +# Used By + +Standalone entry point, invoked directly by a user/script preparing an +offline deployment — not called by other functions in the module. + +# Usage Example + +```python +import rpa as r +r.pack() +# copy the generated rpa_python.zip and rpa.py to the offline machine, +# then there: import rpa as r; r.init() +``` + +# Notes + +- Companion to [`update()`](update.md): `pack()` is for a first offline + install, `update()` is for refreshing an install that was originally + deployed via `pack()`. diff --git a/docs/okf/tagui/send.md b/docs/okf/tagui/send.md new file mode 100644 index 0000000..daeeb29 --- /dev/null +++ b/docs/okf/tagui/send.md @@ -0,0 +1,55 @@ +--- +type: Function +title: tagui.send +description: Sends one TagUI live-mode instruction over the subprocess's stdin and blocks until TagUI reports it is ready for the next one. +resource: tagui.py#L819 +tags: [rpa, tagui, process-lifecycle] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.send + +# Responsibility + +The single choke point almost every UI-interaction function in +[tagui](../tagui.md) funnels through. Escapes control characters in the +instruction string, writes it to the TagUI process's stdin wrapped in echo +markers (`[RPA][] - ...` / `... - listening for inputs`), then loops +calling [`_ready()`](../tagui.md) until TagUI's stdout confirms it consumed +the instruction and is listening again. + +# Public Interface + +```python +send(tagui_instruction=None) # returns True/False +``` + +# Dependencies + +- Uses `_tagui_write()`/`_tagui_read()` (subprocess stdin/stdout) and + `_ready()` from [tagui](../tagui.md). + +# Used By + +- Nearly every UI-interaction function in [tagui](../tagui.md) (`click`, + `type`, `select`, `frame`, `popup`, `dom`, `keyboard`, `mouse`, + `vision`, `timeout`, and others) builds a TagUI command string and + passes it to `send()`. + +# Usage Example + +```python +# internal usage pattern, e.g. inside click(): +send('click ' + _sdq(element_identifier)) +``` + +# Notes + +- Requires `init()` to have been called (`_tagui_started` True); errors + via `show_error()` otherwise. +- Escapes `\`, `\n`, `\r`, `\t`, `\a`, `\b`, `\f` and a special + `[BACKSLASH_QUOTE]` marker (used by [`_esq()`](../tagui.md) for embedded + single quotes) before writing to the subprocess. +- If the TagUI process has already died (`_process.poll() is not None`), + resets `_tagui_started`/`_tagui_visual`/`_tagui_chrome` to False and + errors instead of writing to a dead pipe. diff --git a/docs/okf/tagui/setup.md b/docs/okf/tagui/setup.md new file mode 100644 index 0000000..4702718 --- /dev/null +++ b/docs/okf/tagui/setup.md @@ -0,0 +1,57 @@ +--- +type: Function +title: tagui.setup +description: Downloads and installs TagUI into the user's home folder (or APPDATA on Windows), applying per-OS patches. +resource: tagui.py#L318 +tags: [rpa, tagui, installation] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.setup + +# Responsibility + +Installs TagUI so [`init()`](init.md) can launch it. Called automatically +by `init()` the first time it can't find the TagUI executable, or can be +run standalone. Downloads the OS-specific TagUI zip (or unpacks an +existing local `rpa_python.zip` produced by [`pack()`](pack.md) for +offline installs), unzips it to `tagui_location()`, syncs the latest +"delta" files, and applies macOS-specific fixes (PhantomJS upgrade, +`python` → `python3` patch) and Linux permission/PHP checks. + +# Public Interface + +```python +setup() # no arguments; returns True/False +``` + +# Dependencies + +- [tagui.download](download.md) — fetches the TagUI zip and any patch + assets (vcredist, PhantomJS) from GitHub-hosted mirrors. +- Uses `unzip()`, `_tagui_delta()`, `_patch_macos_pjs()`, + `_patch_macos_py3()`, and `tagui_location()` from [tagui](../tagui.md). + +# Used By + +- [tagui.init](init.md) — invoked automatically when the TagUI executable + is not found at the expected location. +- [tagui.pack](pack.md) — indirectly, via the temporary `init()`/`close()` + cycle it performs before zipping the installation. + +# Usage Example + +```python +import rpa as r +r.setup() # or just call r.init() directly, which triggers this on first run +``` + +# Notes + +- Two installation pathways: primary (download `TagUI_.zip` from the + internet) and secondary (unzip a local `rpa_python.zip`, the artifact + produced by [`pack()`](pack.md), for air-gapped machines). +- On Linux, requires `php` to already be installed and printed install + instructions if it can't detect it; on Windows, auto-downloads and runs + the Visual C++ Redistributable (`vcredist_x86.exe`) if TagUI's bundled + PHP fails to run. diff --git a/docs/okf/tagui/update.md b/docs/okf/tagui/update.md new file mode 100644 index 0000000..08abe69 --- /dev/null +++ b/docs/okf/tagui/update.md @@ -0,0 +1,56 @@ +--- +type: Function +title: tagui.update +description: Builds a self-contained update.py that embeds the latest TagUI delta files (base64-zipped) for updating an existing offline/air-gapped installation. +resource: tagui.py#L683 +tags: [rpa, tagui, offline-deployment] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.update + +# Responsibility + +Companion to [`pack()`](pack.md) for machines that already have RPA for +Python installed offline. Downloads the latest `tagui.py` and TagUI +"delta" files (same list as [`_tagui_delta()`](../tagui.md)), zips them, +base64-encodes the zip, and writes it into a generated `update.py` script +(along with unzip/install logic) that can be copied or emailed to the +offline target and run there with no separate download step. + +# Public Interface + +```python +update() # no arguments; returns True/False +``` + +# Dependencies + +- [tagui.download](download.md) — fetches the latest `tagui.py` and each + delta file from the project's GitHub-hosted mirrors. +- Uses `load()`, `dump()`, `write()`, and `unzip()` (via the generated + `update.py`'s embedded call to `r.unzip(...)`) from + [tagui](../tagui.md). + +# Used By + +Standalone entry point — generates a script meant to be run independently +on the target machine, not called by other functions in this module. + +# Usage Example + +```python +import rpa as r +r.update() +# copy or email the generated update.py to the offline machine, then: +# python update.py +``` + +# Notes + +- The generated `update.py` is fully self-contained: it embeds the update + zip as a base64 string literal and, when run, decodes/unzips it into the + TagUI installation directory and moves the refreshed `rpa.py` into the + installed package folder. +- Reads the target version number out of the freshly downloaded + `tagui.py`'s `__version__` string to report/name the update. From 68de1248258fbb978a8aaa40613cf090dba464e5 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 22 Jul 2026 12:56:08 +0000 Subject: [PATCH 2/2] docs: deepen OKF documentation for tagui's public API Add 15 new Function concepts covering the ~58 tagui.py public functions that the initial scan had folded into a single summary table, grouped by shared implementation pattern, plus concepts for the live-mode wire protocol and the private per-OS setup/patch helpers. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_011MR7MDaEK9Dpa2t1rL4b5T --- docs/okf/log.md | 12 ++++ docs/okf/tagui.md | 98 ++++++++++++++-------------- docs/okf/tagui/click-family.md | 62 ++++++++++++++++++ docs/okf/tagui/clipboard.md | 43 ++++++++++++ docs/okf/tagui/config-utility.md | 78 ++++++++++++++++++++++ docs/okf/tagui/dom-run.md | 59 +++++++++++++++++ docs/okf/tagui/exist-present.md | 76 +++++++++++++++++++++ docs/okf/tagui/frame-popup.md | 66 +++++++++++++++++++ docs/okf/tagui/hover.md | 42 ++++++++++++ docs/okf/tagui/index.md | 62 ++++++++++++++---- docs/okf/tagui/live-mode-protocol.md | 97 +++++++++++++++++++++++++++ docs/okf/tagui/misc.md | 69 ++++++++++++++++++++ docs/okf/tagui/mouse-position.md | 44 +++++++++++++ docs/okf/tagui/read-snap.md | 70 ++++++++++++++++++++ docs/okf/tagui/setup-internals.md | 76 +++++++++++++++++++++ docs/okf/tagui/state-readers.md | 50 ++++++++++++++ docs/okf/tagui/string-utility.md | 49 ++++++++++++++ docs/okf/tagui/table-upload-bin.md | 66 +++++++++++++++++++ docs/okf/tagui/type-select.md | 69 ++++++++++++++++++++ docs/okf/tagui/url.md | 48 ++++++++++++++ docs/okf/tagui/visual-input.md | 51 +++++++++++++++ 21 files changed, 1224 insertions(+), 63 deletions(-) create mode 100644 docs/okf/tagui/click-family.md create mode 100644 docs/okf/tagui/clipboard.md create mode 100644 docs/okf/tagui/config-utility.md create mode 100644 docs/okf/tagui/dom-run.md create mode 100644 docs/okf/tagui/exist-present.md create mode 100644 docs/okf/tagui/frame-popup.md create mode 100644 docs/okf/tagui/hover.md create mode 100644 docs/okf/tagui/live-mode-protocol.md create mode 100644 docs/okf/tagui/misc.md create mode 100644 docs/okf/tagui/mouse-position.md create mode 100644 docs/okf/tagui/read-snap.md create mode 100644 docs/okf/tagui/setup-internals.md create mode 100644 docs/okf/tagui/state-readers.md create mode 100644 docs/okf/tagui/string-utility.md create mode 100644 docs/okf/tagui/table-upload-bin.md create mode 100644 docs/okf/tagui/type-select.md create mode 100644 docs/okf/tagui/url.md create mode 100644 docs/okf/tagui/visual-input.md diff --git a/docs/okf/log.md b/docs/okf/log.md index 0f9e3c5..4b45981 100644 --- a/docs/okf/log.md +++ b/docs/okf/log.md @@ -1,6 +1,18 @@ # Directory Update Log ## 2026-07-22 +- **Added**: Deepened the initial scan after feedback that the bundle was + too shallow — 15 new `tagui/` Function concepts covering the ~58 + public functions previously only listed in `tagui.md`'s Public + Interface table (grouped by shared implementation pattern: + `exist-present`, `click-family`, `hover`, `type-select`, `read-snap`, + `url`, `frame-popup`, `dom-run`, `table-upload-bin`, `visual-input`, + `mouse-position`, `clipboard`, `config-utility`, `state-readers`, + `misc`, `string-utility`), plus `live-mode-protocol` (the echo-marker + instruction protocol behind `init`/`send`/`close`) and + `setup-internals` (the private per-OS patch/delta helpers). Updated + `tagui.md` and `tagui/index.md` to link into the new concepts instead + of inlining bare signatures. - **Initial scan**: Generated the OKF bundle for `marcelocecin/RPA-Python` at commit `8259b4c`. Documented the `tagui` module (1 Module concept, 7 Function concepts for entry points with non-trivial logic), the `rpa` diff --git a/docs/okf/tagui.md b/docs/okf/tagui.md index 7ebff53..748fa95 100644 --- a/docs/okf/tagui.md +++ b/docs/okf/tagui.md @@ -29,8 +29,10 @@ regenerates it from `tagui.py` on every run. # Public Interface -Process lifecycle and setup (see individual concepts for the ones with -non-trivial logic): +Process lifecycle, setup, and the wire protocol connecting them — see +[tagui/live-mode-protocol](tagui/live-mode-protocol.md) for how these fit +together, and [tagui/setup-internals](tagui/setup-internals.md) for the +private per-OS helpers they lean on: ```python setup() # tagui/setup.md @@ -43,72 +45,70 @@ update() # download(download_url=None, filename_to_save=None) # tagui/download.md ``` -Configuration / diagnostics: +Configuration / diagnostics — see +[tagui/config-utility](tagui/config-utility.md): ```python -debug(on_off=None) # get/set debug mode (echoes TagUI output to stdout) -error(on_off=None) # get/set whether errors raise Exception instead of just printing -show_error(error_message=None) # print or raise the given error message, per error() mode -tagui_location(location=None) # get/set the folder TagUI is installed to (default: user home) -timeout(timeout_in_seconds=None) # get/set the default wait timeout (seconds) for UI elements -download_location(location=None) # get/set the browser's file download directory -coord(x_coordinate=0, y_coordinate=0) # build an "(x,y)" coordinate string accepted by other calls +coord(x_coordinate=0, y_coordinate=0) +debug(on_off=None) +error(on_off=None) +show_error(error_message=None) +tagui_location(location=None) +unzip(file_to_unzip=None, unzip_location=None) +timeout(timeout_in_seconds=None) +download_location(location=None) ``` -Web / desktop UI interaction (each waits for readiness via `_started()`/ -`exist()` then delegates to `send()`): +Web / desktop UI interaction — each waits for readiness via `_started()`/ +[`exist()`](tagui/exist-present.md) then delegates to +[`send()`](tagui/send.md): ```python -url(webpage_url=None) # navigate, or return current URL -exist(element_identifier=None) # True if element/coordinate exists (waits up to timeout) -present(element_identifier=None) # True if element/coordinate is present now (no wait) -click(element_identifier=None, test_coordinate=None) -rclick(element_identifier=None, test_coordinate=None) # right-click -dclick(element_identifier=None, test_coordinate=None) # double-click -hover(element_identifier=None, test_coordinate=None) -type(element_identifier=None, text=None, test_coordinate=None) -select(element_identifier=None, option_value=None, test_coordinate=None) -read(element_identifier=None, test_coordinate=None) -snap(element_identifier=None, filename_to_save=None, test_coordinate=None) -table(element_identifier=None, filename_to_save=None) # export an HTML table to CSV -upload(element_identifier=None, filename_to_upload=None) -frame(main_frame=None, sub_frame=None) # switch webpage context into an iframe -popup(string_in_url=None) # switch webpage context into a popup/tab -count(element_identifier=None) -title() -text() -dom(statement_to_run=None) # run and return an arbitrary JS/DOM statement (chrome mode) -api(url_to_query=None) # stub; recommends using the `requests` package instead +url(webpage_url=None) # tagui/url.md +exist(element_identifier=None) / present(element_identifier=None) # tagui/exist-present.md +click(...) / rclick(...) / dclick(...) # tagui/click-family.md +hover(element_identifier=None, test_coordinate=None) # tagui/hover.md +type(...) / select(...) # tagui/type-select.md +read(...) / snap(...) # tagui/read-snap.md +table(...) / upload(...) / bin(...) # tagui/table-upload-bin.md +frame(main_frame=None, sub_frame=None) / popup(string_in_url=None) # tagui/frame-popup.md +count(element_identifier=None) / title() / text() / timer() # tagui/state-readers.md +dom(statement_to_run=None) / run(command_to_run=None) # tagui/dom-run.md +api(url_to_query=None) # stub; recommends using the `requests` package instead ``` -Keyboard / mouse / vision (require `init(visual_automation=True)`): +Keyboard / mouse / vision (require `init(visual_automation=True)`) — see +[tagui/visual-input](tagui/visual-input.md), +[tagui/mouse-position](tagui/mouse-position.md), +[tagui/clipboard](tagui/clipboard.md): ```python -keyboard(keys_and_modifiers=None) -mouse(mouse_action=None) # 'down' or 'up' -vision(command_to_run=None) +keyboard(keys_and_modifiers=None) / mouse(mouse_action=None) / vision(command_to_run=None) mouse_xy() / mouse_x() / mouse_y() -clipboard(text_to_put=None) # get/set OS clipboard +clipboard(text_to_put=None) ``` -Misc utilities: +Misc — see [tagui/misc](tagui/misc.md) and +[tagui/string-utility](tagui/string-utility.md): ```python wait(delay_in_seconds=5.0) check(condition_to_check=None, text_if_true='', text_if_false='') -ask(text_to_prompt='') # JS prompt() in chrome mode, console input otherwise -focus(app_to_focus=None) # bring a desktop app window to the foreground (Windows/macOS only) -run(command_to_run=None) # run a shell command, return its output -timer() # elapsed seconds of current TagUI flow -telegram(telegram_id=None, text_to_send=None, custom_endpoint=None) # deprecated, see Notes -bin(file_to_bin=None, password=None, server='https://tebel.org/bin/') # deprecated, see Notes -unzip(file_to_unzip=None, unzip_location=None) -load(filename_to_load=None) -echo(text_to_echo='') +ask(text_to_prompt='') +focus(app_to_focus=None) +telegram(telegram_id=None, text_to_send=None, custom_endpoint=None) # deprecated +get_text(source_text=None, left=None, right=None, count=1) +del_chars(source_text=None, characters=None) +``` + +Trivial file I/O one-liners (no dedicated concept — genuinely simple +wrappers around Python's own `open()`/`print`): + +```python +load(filename_to_load=None) # read a file's contents +echo(text_to_echo='') # print() dump(text_to_dump=None, filename_to_save=None) # overwrite file with text write(text_to_write=None, filename_to_save=None) # append text to file -get_text(source_text=None, left=None, right=None, count=1) # substring between two delimiters -del_chars(source_text=None, characters=None) # strip given characters from a string ``` # Dependencies diff --git a/docs/okf/tagui/click-family.md b/docs/okf/tagui/click-family.md new file mode 100644 index 0000000..af94c9d --- /dev/null +++ b/docs/okf/tagui/click-family.md @@ -0,0 +1,62 @@ +--- +type: Function +title: tagui.click / tagui.rclick / tagui.dclick +description: Click, right-click, or double-click a UI element or (x, y) screen coordinate. +resource: tagui.py#L1010 +tags: [rpa, tagui, ui-interaction] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.click / tagui.rclick / tagui.dclick + +# Responsibility + +Three functions with an identical body, differing only in the TagUI +command word they send (`click`, `rclick`, `dclick`). Each requires +`init()` to have run, requires a non-empty `element_identifier`, checks +[`exist()`](exist-present.md) first (erroring with "cannot find ..." if +it doesn't), then sends the click command via [`send()`](send.md). + +`test_coordinate`, if given as an `int`, is treated as the y-coordinate +and combined with `element_identifier` (treated as x) via +[`coord()`](config-utility.md) into an `"(x,y)"` string before anything +else runs — i.e. `click(600, 300)` and `click('(600,300)')` are +equivalent. + +# Public Interface + +```python +click(element_identifier=None, test_coordinate=None) # left click +rclick(element_identifier=None, test_coordinate=None) # right click +dclick(element_identifier=None, test_coordinate=None) # double click +``` + +# Dependencies + +- [tagui.exist-present](exist-present.md) — existence pre-check. +- [tagui.send](send.md) — issues the `click`/`rclick`/`dclick` TagUI + command. +- [tagui.config-utility](config-utility.md) — `coord()` for the + `(x, y)` overload. + +# Used By + +- [sample](../sample.md) — `r.click('ybar-search')`. +- `bin()` (see [table/upload/bin](table-upload-bin.md)) — clicks through + the upload flow. + +# Usage Example + +```python +r.click('//*[@id="submit"]') # by XPath +r.click(600, 300) # by x, y coordinate (visual automation) +r.rclick('Submit Form.png') # by image / OCR text match +r.dclick('icon.png') +``` + +# Notes + +- No dedicated identifier-type validation beyond `exist()` — any string + accepted by TagUI's own `click`/`rclick`/`dclick` step works (XPath, + CSS selector, DOM attribute, `.png`/`.bmp` image, OCR text, or + coordinate). diff --git a/docs/okf/tagui/clipboard.md b/docs/okf/tagui/clipboard.md new file mode 100644 index 0000000..5e07c79 --- /dev/null +++ b/docs/okf/tagui/clipboard.md @@ -0,0 +1,43 @@ +--- +type: Function +title: tagui.clipboard +description: Get or set the OS clipboard's text content (visual automation only). +resource: tagui.py#L1819 +tags: [rpa, tagui, visual-automation] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.clipboard + +# Responsibility + +Dual-purpose like [`url()`](url.md): requires `init(visual_automation=True)`. +Called with no argument, it dumps and returns the current clipboard +content (`dump clipboard() to rpa_python.txt`). Called with +`text_to_put`, it instead sends a raw `js clipboard('')` instruction +that sets it, with single quotes swapped to the `[BACKSLASH_QUOTE]` +marker that [`send()`](send.md) unescapes. + +# Public Interface + +```python +clipboard(text_to_put=None) # returns current clipboard text, or True/False when setting +``` + +# Dependencies + +- [tagui.send](send.md). +- Uses `_started()`, `_visual()`, `_tagui_output()` from + [tagui](../tagui.md). + +# Used By + +Standalone call; not depended on by other documented functions. + +# Usage Example + +```python +r.init(visual_automation=True) +r.clipboard('hello world') +current = r.clipboard() +``` diff --git a/docs/okf/tagui/config-utility.md b/docs/okf/tagui/config-utility.md new file mode 100644 index 0000000..b3fdb82 --- /dev/null +++ b/docs/okf/tagui/config-utility.md @@ -0,0 +1,78 @@ +--- +type: Function +title: tagui.coord / debug / error / show_error / tagui_location / unzip / timeout / download_location +description: Small configuration and utility getters/setters used throughout the module — coordinate formatting, debug/error mode, install location, timeout, and download directory. +resource: tagui.py#L261 +tags: [rpa, tagui, configuration] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.coord / debug / error / show_error / tagui_location / unzip / timeout / download_location + +# Responsibility + +Grouped because each is a small get-or-set-if-given accessor around one +piece of module state, with no TagUI process interaction of its own +(except `timeout()`, which also forwards to TagUI via `send()`): + +- `coord(x, y)` — pure string formatting: `'(' + str(x) + ',' + str(y) + ')'`. + The building block every coordinate-overloaded function + ([click family](click-family.md), [type/select](type-select.md), + [read/snap](read-snap.md), [exist/present](exist-present.md)) uses to + turn integer arguments into the identifier string TagUI expects. +- `debug(on_off)` — get/set `_tagui_debug`; when on, [`_ready()`](live-mode-protocol.md) + echoes raw TagUI subprocess output to stdout, and + [`close()`](close.md) skips deleting the `.log`/`.txt` output files. + Passing a non-int value instead sends it as a TagUI comment + (`// `) rather than toggling debug mode — an odd overload worth + knowing about. +- `error(on_off)` — get/set `_tagui_error`; when True, + [`show_error()`](#) raises `Exception` instead of just printing. +- `show_error(error_message)` — the module's single error-reporting + choke point: prints or raises depending on `error()`, always returns + `False` (so callers can `return show_error(...)`). +- `tagui_location(location)` — get/set the folder TagUI is/will be + installed to (defaults to `%APPDATA%` on Windows, else `~`). Read by + [`setup()`](setup.md)/[`init()`](init.md) to locate the executable. +- `unzip(file_to_unzip, unzip_location)` — thin `zipfile` wrapper used by + [`setup()`](setup.md) and [setup internals](setup-internals.md). +- `timeout(timeout_in_seconds)` — get/set `_tagui_timeout` (default 10.0s, + the poll ceiling [`exist()`](exist-present.md) uses inside TagUI's own + JS); also forwards the new value to TagUI via `send('timeout ...')` + when setting. +- `download_location(location)` — get/set the browser's download + directory by sending a Chrome DevTools Protocol + `Page.setDownloadBehavior` instruction; rejects locations containing a + single quote (would break the raw JS string it builds). + +# Public Interface + +```python +coord(x_coordinate=0, y_coordinate=0) # -> str "(x,y)" +debug(on_off=None) # -> bool +error(on_off=None) # -> bool +show_error(error_message=None) # -> False (side effect: print/raise) +tagui_location(location=None) # -> str +unzip(file_to_unzip=None, unzip_location=None) # -> True/False +timeout(timeout_in_seconds=None) # -> float +download_location(location=None) # -> str or True/False +``` + +# Dependencies + +- `timeout()`/`download_location()` use [tagui.send](send.md). +- `setup()` uses `unzip()`/`tagui_location()` directly (see + [tagui.setup](setup.md)). + +# Used By + +Used pervasively by nearly every other concept in this module — see +individual mentions above. + +# Usage Example + +```python +r.timeout(30) # wait up to 30s for elements to exist +r.error(True) # raise exceptions instead of printing errors +r.tagui_location('/opt/tagui_home') +``` diff --git a/docs/okf/tagui/dom-run.md b/docs/okf/tagui/dom-run.md new file mode 100644 index 0000000..531b318 --- /dev/null +++ b/docs/okf/tagui/dom-run.md @@ -0,0 +1,59 @@ +--- +type: Function +title: tagui.dom / tagui.run +description: Execute an arbitrary JavaScript/DOM statement in the browser (dom), or an arbitrary shell command on the host (run), returning the result. +resource: tagui.py#L1618 +tags: [rpa, tagui, escape-hatch] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.dom / tagui.run + +# Responsibility + +Both are deliberate escape hatches for anything the rest of the API +doesn't cover directly. + +- `dom(statement_to_run)`: requires `init(chrome_browser=True)`. Sends + `dom ` to TagUI (which evaluates it in the page's JS + context and stores the result in TagUI's `dom_result` variable), then + dumps and reads that result back via + `dump dom_result to rpa_python.txt`. +- `run(command_to_run)`: does not require `init()` at all — it's a plain + `subprocess.check_output` wrapper. Appends `; exit 0` (or `& exit 0` on + Windows) to the command so a non-zero exit code from the command + itself doesn't raise `CalledProcessError`, and returns combined + stdout+stderr. + +# Public Interface + +```python +dom(statement_to_run=None) # returns the JS result as a string +run(command_to_run=None) # returns combined stdout/stderr as a string +``` + +# Dependencies + +- `dom()` uses [tagui.send](send.md) and `_tagui_output()`. +- `run()` uses only the standard library `subprocess` module — no + dependency on the TagUI subprocess or `init()`. + +# Used By + +Standalone escape-hatch calls; not depended on by other documented +functions in this module. + +# Usage Example + +```python +page_height = r.dom('return document.body.scrollHeight') +output = r.run('ls -la') +``` + +# Notes + +- `run()` executes with `shell=True`, so any untrusted input passed as + `command_to_run` is a shell-injection risk — this is inherent to the + function's purpose (arbitrary shell execution) rather than a bug, but + callers building `command_to_run` from external input should sanitize + it themselves. diff --git a/docs/okf/tagui/exist-present.md b/docs/okf/tagui/exist-present.md new file mode 100644 index 0000000..0722d1e --- /dev/null +++ b/docs/okf/tagui/exist-present.md @@ -0,0 +1,76 @@ +--- +type: Function +title: tagui.exist / tagui.present +description: Check whether a UI element, screen keyword, or coordinate exists/is present on screen, with special handling for visual-automation keywords and OCR fallback. +resource: tagui.py#L946 +tags: [rpa, tagui, ui-interaction, visual-automation] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.exist / tagui.present + +# Responsibility + +Both functions answer "can I interact with this identifier?" and share +identical special-case logic; the only difference is that `exist()` +delegates to TagUI's own `exist()` JS helper (which polls up to the +current [`timeout()`](../tagui.md) before giving up — see +[`_tagui_local_js`](setup-internals.md)), while `present()` checks once, +immediately, with no wait. Almost every UI-interaction function +(`click`, `type`, `read`, `snap`, ...) calls `exist()` first as a +guard before sending its real instruction. + +Special-cased `element_identifier` values, handled identically in both +functions: +- `'page.png'` / `'page.bmp'` (case-insensitive) — always exist/present if + `init(visual_automation=True)` was used, since "the computer screen + always exists"; errors otherwise. +- Any other `.png`/`.bmp` string — requires visual automation; errors if + not enabled. +- A literal `"(x,y)"` or `"(x,y,z)"` coordinate string with no alphabetic + characters (as produced by [`coord()`](config-utility.md)) — always + exists/present under visual automation, on the assumption on-screen + coordinates are always valid. +- Anything else — sent to TagUI as a real existence check + (`exist(...)`/`present(...)` JS call via [`send()`](send.md)), whose + result comes back through the `rpa_python.txt` output file. + +# Public Interface + +```python +exist(element_identifier=None) # returns True/False, waits up to timeout() +present(element_identifier=None) # returns True/False, no wait +``` + +# Dependencies + +- [tagui.send](send.md) — issues the underlying `exist(...)`/`present(...)` + TagUI JS calls and reads the boolean result back via + `_tagui_output()`. +- Uses `_visual()`, `_started()`, `_sdq()` from [tagui](../tagui.md). + +# Used By + +- Nearly every UI-interaction concept — [click family](click-family.md), + [hover](hover.md), [type/select](type-select.md), [read/snap](read-snap.md), + [table/upload/bin](table-upload-bin.md) — calls `exist()` before acting, + to fail fast with a clear error instead of letting TagUI time out + silently. + +# Usage Example + +```python +if r.exist('//*[@id="submit"]'): + r.click('//*[@id="submit"]') + +if r.present('page.png'): # requires init(visual_automation=True) + print('visual automation is active') +``` + +# Notes + +- `present()`'s "return False for a coordinate/keyword with no visual + automation" branches print an error via `show_error()` even though the + function is often used just to probe (`if r.present(...)`) — callers + relying on a silent `False` should be aware output may still appear on + stdout / raise if `error(True)` is set. diff --git a/docs/okf/tagui/frame-popup.md b/docs/okf/tagui/frame-popup.md new file mode 100644 index 0000000..39b8d28 --- /dev/null +++ b/docs/okf/tagui/frame-popup.md @@ -0,0 +1,66 @@ +--- +type: Function +title: tagui.frame / tagui.popup +description: Switch the webpage's JS evaluation context into an iframe/sub-iframe, or into a popup/new-tab matching a URL substring. +resource: tagui.py#L1534 +tags: [rpa, tagui, browser, chrome-devtools-protocol] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.frame / tagui.popup + +# Responsibility + +Both require `init(chrome_browser=True)` and work by sending raw +`js ...` TagUI instructions (via [`send()`](send.md)) that manipulate +global JS state (`chrome_context`, `chrome_targetid`) used internally by +TagUI's Chrome DevTools Protocol integration — there is no dedicated +TagUI command for either operation, so both hand-roll the JS. + +- `frame(main_frame, sub_frame)`: always resets context to the document + root first. With no arguments, that reset is all it does (returns + True). With `main_frame`, it locates an iframe by `@name`/`@id` via an + XPath existence check, computes its bounding rect (for later + coordinate-based interaction), and repoints `chrome_context` at that + iframe's `contentDocument`. `sub_frame`, if given, repeats the process + one level deeper. +- `popup(string_in_url)`: always detaches any currently-attached popup + target first. With no argument, that's all it does. With a URL + substring, it lists all Chrome targets via the + `Target.getTargets`/`Target.attachToTarget` CDP calls, finds the first + target whose `url` contains the substring, and sets `chrome_targetid` + to its new session ID so subsequent calls act on that tab/popup. + +# Public Interface + +```python +frame(main_frame=None, sub_frame=None) # returns True/False +popup(string_in_url=None) # returns True/False +``` + +# Dependencies + +- [tagui.send](send.md) — every step is a raw `js ...` instruction. +- [tagui.exist-present](exist-present.md) — `frame()` uses `exist()` to + confirm the target iframe is present before proceeding. + +# Used By + +Standalone browser-context calls; not depended on by other documented +functions in this module. + +# Usage Example + +```python +r.frame('payment-iframe') # switch into an iframe by name/id +r.frame() # switch back to the main document +r.popup('checkout') # switch into a popup/tab whose URL contains 'checkout' +r.popup() # detach from the current popup +``` + +# Notes + +- Neither function validates that the sent JS actually succeeded beyond + what's checked explicitly (`frame()` checks `exist()` for the iframe; + `popup()` checks that `chrome_targetid` ended up non-empty) — malformed + frame/tab state can otherwise pass silently. diff --git a/docs/okf/tagui/hover.md b/docs/okf/tagui/hover.md new file mode 100644 index 0000000..84336b8 --- /dev/null +++ b/docs/okf/tagui/hover.md @@ -0,0 +1,42 @@ +--- +type: Function +title: tagui.hover +description: Hover the mouse/pointer over a UI element or (x, y) screen coordinate. +resource: tagui.py#L1076 +tags: [rpa, tagui, ui-interaction] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.hover + +# Responsibility + +Same structure as the [click family](click-family.md): requires `init()`, +requires a non-empty `element_identifier`, resolves an optional integer +`test_coordinate` into an `(x, y)` string via +[`coord()`](config-utility.md), checks [`exist()`](exist-present.md), +then sends a `hover` TagUI command. + +# Public Interface + +```python +hover(element_identifier=None, test_coordinate=None) +``` + +# Dependencies + +- [tagui.exist-present](exist-present.md), [tagui.send](send.md), + [tagui.config-utility](config-utility.md) — same roles as in the + [click family](click-family.md). + +# Used By + +Standalone UI-interaction call; no other documented function in this +module depends on it. + +# Usage Example + +```python +r.hover('menu-item') +r.hover(400, 250) # x, y coordinate, visual automation +``` diff --git a/docs/okf/tagui/index.md b/docs/okf/tagui/index.md index a1abd7f..2f35dba 100644 --- a/docs/okf/tagui/index.md +++ b/docs/okf/tagui/index.md @@ -1,21 +1,55 @@ -# tagui — Key Functions +# tagui — Function Concepts -Function-level concepts for the entry points in [tagui](../tagui.md) that -have non-trivial logic (process lifecycle, installation, offline -packaging). The rest of the module's public functions are thin one-line -wrappers around [`send()`](send.md) and are catalogued in the module's own -Public Interface table rather than documented individually. +Function-level concepts for [tagui](../tagui.md), grouped by shared +implementation pattern where several functions have (near-)identical +bodies. Only `load`/`echo`/`dump`/`write` are left undocumented +individually — genuinely trivial one-line file/print wrappers, catalogued +in the module's own Public Interface table instead. +Process lifecycle, installation, and offline packaging: + +* [live-mode-protocol](live-mode-protocol.md) - the echo-marker + instruction protocol connecting `init`/`send`/`close`. * [setup](setup.md) - downloads and installs TagUI for the current OS. -* [init](init.md) - starts the TagUI subprocess and waits for it to become - ready. -* [send](send.md) - sends one instruction to the running TagUI process and - waits for it to finish. -* [close](close.md) - terminates the TagUI subprocess and cleans up - generated files. -* [pack](pack.md) - bundles a TagUI installation for offline ("air-gapped") - deployment. +* [setup-internals](setup-internals.md) - the private per-OS helpers + `setup()`/`init()`/`pack()` all depend on. +* [init](init.md) - starts the TagUI subprocess and waits for it to + become ready. +* [send](send.md) - sends one instruction to the running TagUI process. +* [close](close.md) - terminates the TagUI subprocess and cleans up. +* [pack](pack.md) - bundles a TagUI installation for offline deployment. * [update](update.md) - builds a self-extracting update script for an offline deployment. * [download](download.md) - Python 2/3-compatible URL-to-file download helper used throughout the module. + +Web / desktop UI interaction: + +* [exist-present](exist-present.md) - `exist()`/`present()`, the + existence checks nearly everything else guards on. +* [click-family](click-family.md) - `click()`/`rclick()`/`dclick()`. +* [hover](hover.md) - `hover()`. +* [type-select](type-select.md) - `type()`/`select()`. +* [read-snap](read-snap.md) - `read()`/`snap()`. +* [table-upload-bin](table-upload-bin.md) - `table()`/`upload()`/`bin()` + (`bin()` deprecated). +* [url](url.md) - `url()`, navigate or query current URL. +* [frame-popup](frame-popup.md) - `frame()`/`popup()`, iframe/tab context + switching. +* [state-readers](state-readers.md) - `count()`/`title()`/`text()`/`timer()`. +* [dom-run](dom-run.md) - `dom()`/`run()`, JS/shell escape hatches. + +Visual automation (`init(visual_automation=True)`): + +* [visual-input](visual-input.md) - `keyboard()`/`mouse()`/`vision()`. +* [mouse-position](mouse-position.md) - `mouse_xy()`/`mouse_x()`/`mouse_y()`. +* [clipboard](clipboard.md) - `clipboard()`. + +Misc / utility: + +* [config-utility](config-utility.md) - `coord()`, `debug()`, `error()`, + `show_error()`, `tagui_location()`, `unzip()`, `timeout()`, + `download_location()`. +* [misc](misc.md) - `ask()`, `check()`, `wait()`, `focus()`, `telegram()` + (deprecated). +* [string-utility](string-utility.md) - `get_text()`/`del_chars()`. diff --git a/docs/okf/tagui/live-mode-protocol.md b/docs/okf/tagui/live-mode-protocol.md new file mode 100644 index 0000000..9192b56 --- /dev/null +++ b/docs/okf/tagui/live-mode-protocol.md @@ -0,0 +1,97 @@ +--- +type: Module +title: TagUI live-mode instruction protocol +description: The stdin/stdout echo-marker protocol that init(), send(), close(), and _ready() use together to synchronize each instruction with the TagUI subprocess. +resource: tagui.py#L127 +tags: [rpa, tagui, protocol, subprocess] +timestamp: 2026-07-22T09:58:59Z +--- + +# TagUI live-mode instruction protocol + +# Responsibility + +Explains the wire protocol underlying [`init()`](init.md), +[`send()`](send.md), [`close()`](close.md), and the private helpers they +share (`_tagui_read`, `_tagui_write`, `_ready`, `_tagui_output`) — none of +which is documented as a coherent whole in any single function's docs. + +TagUI, once launched in "live mode" (`tagui rpa_python `), +reads instructions from its own stdin one line at a time and prints +output to stdout. This module layers a synchronous request/response +protocol on top of that raw pipe using **echo markers**: + +1. Every instruction is assigned an incrementing integer ID + (`_tagui_id`, reset to 0 in `init()`). +2. Before sending an instruction, `send()` writes an echo line: + `echo "[RPA][] - "`, then the actual + instruction, then a second echo line: + `echo "[RPA][] - listening for inputs"`. +3. `_ready()` reads TagUI's stdout line by line + (`_tagui_read()` → `_process.stdout.readline()`) and returns True the + moment it sees a line that starts with `[RPA][` and ends with + `] - listening for inputs` — i.e. TagUI has finished echoing back the + "listening" marker, proving the prior instruction fully executed. +4. `send()`/`init()` spin in a tight `while _tagui_started and not + _ready(): pass` loop until that happens, then increment `_tagui_id` + and return control to the caller. +5. For instructions that produce a value (e.g. `read()`, `url()` with no + argument, `dom()`), the pattern is: send a TagUI expression that + assigns to a TagUI-side variable, then + `send('dump to rpa_python.txt')`, then call + `_tagui_output()`, which polls for `rpa_python.txt` to appear (falling + back to `_tagui_init_directory` if the caller `chdir()`'d away), + reads and deletes it, and returns its contents. +6. `init()` itself uses the same `_ready()` loop, but waits for the + *initial* `LIVE MODE - type done to quit` banner from TagUI before + writing the first two echo lines (`[RPA][STARTED]` and + `[RPA][0] - listening for inputs`) to prime the protocol. +7. `close()` ends the session by writing `echo "[RPA][FINISHED]"` then + `done`, and simply waits for the subprocess to exit + (`while _process.poll() is None: pass`) — it does not go through the + `_ready()` echo-matching loop, since there's no further instruction to + confirm. + +All special characters (`\`, `\n`, `\r`, `\t`, `\a`, `\b`, `\f`) are +escaped by `send()` before writing, since the instruction is embedded +inside a shell `echo` argument; the `[BACKSLASH_QUOTE]` marker used by +[`_esq()`](../tagui.md) round-trips through this same escaping to +represent a literal `'` without breaking TagUI's own quoting rules. + +# Public Interface + +Not a standalone callable — this is the coordination pattern implemented +across: + +```python +send(tagui_instruction=None) # writer side of the protocol +_ready() # reader side: detects the "listening" marker +_tagui_read() / _tagui_write() # raw subprocess.stdin/stdout access +_tagui_output() # polls/reads/deletes rpa_python.txt for return values +``` + +# Dependencies + +None beyond the standard library (`subprocess`, `os`, `time`). + +# Used By + +- [tagui.init](init.md) — primes the protocol on subprocess startup. +- [tagui.send](send.md) — the primary writer. +- [tagui.close](close.md) — sends the terminal `done` instruction (bypasses + the `_ready()` loop). +- Every value-returning function (`read`, `url`, `title`, `text`, + `mouse_xy`, `dom`, ...) relies on the `dump ... to rpa_python.txt` + + `_tagui_output()` half of this protocol. + +# Notes + +- The busy-wait loops (`while ... not _ready(): pass`, + `while _process.poll() is None: pass`) spin the CPU rather than + sleeping between polls — acceptable because TagUI responses are + expected to be fast, but worth knowing if profiling shows unexpected + CPU usage during automation. +- If the TagUI subprocess dies mid-instruction (`_process.poll()` becomes + non-None), both `send()` and `_ready()` detect it and flip + `_tagui_started`/`_tagui_visual`/`_tagui_chrome` back to False rather + than hanging forever. diff --git a/docs/okf/tagui/misc.md b/docs/okf/tagui/misc.md new file mode 100644 index 0000000..da13034 --- /dev/null +++ b/docs/okf/tagui/misc.md @@ -0,0 +1,69 @@ +--- +type: Function +title: tagui.ask / tagui.check / tagui.wait / tagui.focus / tagui.telegram +description: Standalone helpers with no shared implementation pattern — user prompt, conditional print, sleep, desktop app focus, and a deprecated Telegram notifier. +resource: tagui.py#L1277 +tags: [rpa, tagui, misc, deprecated] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.ask / tagui.check / tagui.wait / tagui.focus / tagui.telegram + +# Responsibility + +Five functions grouped only because each is a standalone one-off, not +because they share logic: + +- `ask(text_to_prompt)` — in `init(chrome_browser=True)` mode, shows a + JS `prompt()` dialog via [`dom()`](dom-run.md) and returns what the + user typed; otherwise falls back to a plain console + `input()`/`raw_input()` (Python 2/3). +- `check(condition_to_check, text_if_true, text_if_false)` — prints one + of two messages depending on a boolean and always returns True; a + scripting convenience, no TagUI interaction. +- `wait(delay_in_seconds=5.0)` — `time.sleep()` wrapper. +- `focus(app_to_focus)` — brings a desktop application window to the + foreground. Windows: downloads and runs a `sendKeys.bat` helper (from + a GitHub-hosted mirror, downloaded once, then reused) via `os.system`. + macOS: runs `osascript -e 'tell application "..." to activate'`. Linux + is explicitly unsupported (returns False with an error). +- `telegram(telegram_id, text_to_send, custom_endpoint)` — **deprecated** + (per the project README). Sends a message via a hardcoded relay at + `https://tebel.org/rpapybot/sendMessage.php` (or `custom_endpoint`) + using `urllib`; swallows all exceptions (no internet, bad ID, relay + down) and returns False rather than raising. + +# Public Interface + +```python +ask(text_to_prompt='') # -> str +check(condition_to_check=None, text_if_true='', text_if_false='') # -> True +wait(delay_in_seconds=5.0) # -> True +focus(app_to_focus=None) # -> True/False, Windows/macOS only +telegram(telegram_id=None, text_to_send=None, custom_endpoint=None) # -> True/False +``` + +# Dependencies + +- `ask()` depends on [tagui.dom-run](dom-run.md) (`dom()`) and `_chrome()`. +- `focus()` depends on [tagui.download](download.md) on Windows + (`sendKeys.bat`). + +# Used By + +Standalone calls; not depended on by other documented functions. + +# Usage Example + +```python +name = r.ask('What is your name?') +r.check(name != '', 'got a name', 'no name given') +r.wait(2) +r.focus('Notepad') +``` + +# Notes + +- `telegram()` is explicitly deprecated in the README (relies on a + third-party relay service) — avoid it in new code, same caveat as + [`bin()`](table-upload-bin.md). diff --git a/docs/okf/tagui/mouse-position.md b/docs/okf/tagui/mouse-position.md new file mode 100644 index 0000000..4bfd4e2 --- /dev/null +++ b/docs/okf/tagui/mouse-position.md @@ -0,0 +1,44 @@ +--- +type: Function +title: tagui.mouse_xy / tagui.mouse_x / tagui.mouse_y +description: Return the current mouse pointer position on screen, as a coordinate string or individual x/y integers (visual automation only). +resource: tagui.py#L1780 +tags: [rpa, tagui, visual-automation] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.mouse_xy / tagui.mouse_x / tagui.mouse_y + +# Responsibility + +Three read-only queries with the same shape: require `init()` and +`init(visual_automation=True)`, then `dump () to rpa_python.txt` +and read the result back. `mouse_xy()` returns the raw TagUI-formatted +string; `mouse_x()`/`mouse_y()` each additionally coerce the result to +`int`. + +# Public Interface + +```python +mouse_xy() # returns coordinate string, e.g. "(600,300)" +mouse_x() # returns int +mouse_y() # returns int +``` + +# Dependencies + +- [tagui.send](send.md) — issues `dump mouse_xy()/mouse_x()/mouse_y() to rpa_python.txt`. +- Uses `_started()`, `_visual()`, `_tagui_output()` from + [tagui](../tagui.md). + +# Used By + +Standalone queries; typically paired with the [click family](click-family.md) +or [hover](hover.md) for coordinate-relative automation. + +# Usage Example + +```python +r.init(visual_automation=True) +x, y = r.mouse_x(), r.mouse_y() +``` diff --git a/docs/okf/tagui/read-snap.md b/docs/okf/tagui/read-snap.md new file mode 100644 index 0000000..dc8f09a --- /dev/null +++ b/docs/okf/tagui/read-snap.md @@ -0,0 +1,70 @@ +--- +type: Function +title: tagui.read / tagui.snap +description: Read text/value from a UI element or screen region, or save a screenshot of an element/page/region to a file. +resource: tagui.py#L1168 +tags: [rpa, tagui, ui-interaction] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.read / tagui.snap + +# Responsibility + +`read()` returns text/value content from `element_identifier`; `snap()` +saves a screenshot of it to `filename_to_save`. Both accept either a +normal identifier or up to three trailing integer coordinates that get +folded into a single `"(x1,y1)-(x2,y2)"` region string via +[`coord()`](config-utility.md) (a rectangular area of interest — e.g. +`r.read(200, 200, 600, 400)` reads the region between those two corners). +Both special-case the literal string `'page'` (case-insensitive) to skip +the [`exist()`](exist-present.md) check entirely, since the whole page +is always considered readable/snappable. + +- `read(element_identifier, x1, y1, x2)` — needs all three of + `test_coordinate1/2/3` as ints to build the region string; falls back + to using `element_identifier` directly otherwise. +- `snap(element_identifier, filename_to_save, x1, y1, x2)` — same region + logic, but only triggers if `element_identifier` **and** + `filename_to_save` are themselves ints (i.e. the first two positional + args are actually the region's first corner, and the real filename is + the last argument, `test_coord3`). Also explicitly errors if a region + is partially specified (`test_coord2` set but `test_coord3` missing). + +# Public Interface + +```python +read(element_identifier=None, test_coordinate1=None, + test_coordinate2=None, test_coordinate3=None) +snap(element_identifier=None, filename_to_save=None, + test_coord1=None, test_coord2=None, test_coord3=None) +``` + +# Dependencies + +- [tagui.exist-present](exist-present.md), [tagui.send](send.md), + [tagui.config-utility](config-utility.md) (`coord()`). + +# Used By + +- [sample](../sample.md) — `r.read('ybar-sbq')`, + `r.snap('page', 'results.png')`, `r.snap('logo', 'logo.png')`. + +# Usage Example + +```python +search_text = r.read('ybar-sbq') +r.snap('page', 'results.png') # whole page +r.snap('logo', 'logo.png') # a specific element +r.read(200, 200, 600, 400) # region between two corners +r.snap(200, 200, 600, 400, 'results.png') # screenshot of a region +``` + +# Notes + +- `read()`/`snap()` are the two functions in the module whose region + (rectangle) coordinate overload is genuinely tricky to read from the + signature alone — the parameter names don't reveal that the last + positional argument shifts meaning depending on the earlier arguments' + types. Anyone modifying these functions should preserve the + `isinstance(..., int)` type-sniffing exactly as-is. diff --git a/docs/okf/tagui/setup-internals.md b/docs/okf/tagui/setup-internals.md new file mode 100644 index 0000000..8f89f58 --- /dev/null +++ b/docs/okf/tagui/setup-internals.md @@ -0,0 +1,76 @@ +--- +type: Function +title: TagUI private setup/patch helpers +description: Private per-OS helpers — _tagui_delta, _patch_macos_pjs, _patch_macos_py3, _tagui_local, _python_flow/_visual_flow — that setup(), init(), and pack() all depend on. +resource: tagui.py#L182 +tags: [rpa, tagui, installation, macos, internal] +timestamp: 2026-07-22T09:58:59Z +--- + +# TagUI private setup/patch helpers + +# Responsibility + +Private (`_`-prefixed) functions that encode the module's per-OS +installation and patching policy. Not part of the public API, but +non-trivial enough — and shared across multiple public entry points — to +warrant one dedicated concept rather than being buried inside +[setup](setup.md)/[init](init.md). + +- `_python_flow()` / `_visual_flow()` — write the `rpa_python` "flow" + file TagUI is launched with, selecting non-visual vs. visual-automation + entry flow (the latter adds a dummy `mouse_xy()` trigger line to force + SikuliX/Jython integration to initialize). +- `_tagui_local()` — writes `tagui_local.js`, defining two custom JS + helpers TagUI loads at startup: a polling `exist(element_identifier)` + that waits up to `casper.options.waitTimeout` before giving up (the + actual implementation behind [`exist()`](exist-present.md)'s wait + behavior), and an `add_concat()` shim needed because this module's + Python environment can't use TagUI's native string-templating. +- `_tagui_delta(base_directory)` — downloads a fixed list of "delta" + files (`tagui`, `tagui.cmd`, `end_processes`, `end_processes.cmd`, + `tagui_header.js`, `tagui_parse.php`, `tagui.sikuli/tagui.py`) from a + GitHub-hosted mirror that tracks TagUI's cutting-edge branch, to keep + a stable-but-current TagUI build in sync with this package's release. + Skips re-downloading if a marker file + (`rpa_python_<__version__>`) for the current version already exists. +- `_patch_macos_pjs()` — one-time patch replacing TagUI's bundled + PhantomJS with v2.1.1 on macOS, to work around an OpenSSL + incompatibility with newer macOS versions; renames the old copy to + `phantomjs_old` rather than deleting it. +- `_patch_macos_py3()` — one-time patch on macOS machines that only have + `python3` (no plain `python` command): rewrites the shebang line + (`#!/usr/bin/env python` → `#!/usr/bin/env python3`) in TagUI's bundled + `casperjs`/`slimerjs` helper scripts. + +# Public Interface + +```python +_python_flow() / _visual_flow() # write rpa_python flow file +_tagui_local() # write tagui_local.js +_tagui_delta(base_directory=None) # returns True/False +_patch_macos_pjs() # returns True/False +_patch_macos_py3() # returns True (best-effort) +``` + +# Dependencies + +- [tagui.download](download.md) — `_tagui_delta()`/`_patch_macos_pjs()` + fetch files from GitHub-hosted mirrors. +- Uses `unzip()`, `load()`/`dump()`, `tagui_location()` from + [tagui.config-utility](config-utility.md) / [tagui](../tagui.md). + +# Used By + +- [tagui.setup](setup.md) — calls `_tagui_delta()` after installing, and + `_patch_macos_pjs()`/`_patch_macos_py3()` on macOS. +- [tagui.init](init.md) — calls all five: the flow-file writer matching + `visual_automation`, `_tagui_local()`, `_tagui_delta()`, and the two + macOS patches, on every start. + +# Notes + +- All three "patch"/"delta" functions are intentionally idempotent via a + marker file (`rpa_python_` or `phantomjs_old`/`py3_patched` + directory checks) — safe to call on every `init()` without redoing + work once applied for the current version. diff --git a/docs/okf/tagui/state-readers.md b/docs/okf/tagui/state-readers.md new file mode 100644 index 0000000..499652b --- /dev/null +++ b/docs/okf/tagui/state-readers.md @@ -0,0 +1,50 @@ +--- +type: Function +title: tagui.count / tagui.title / tagui.text / tagui.timer +description: Read-only queries against the current page — matching-element count, page title, visible text, and elapsed flow time. +resource: tagui.py#L1729 +tags: [rpa, tagui, ui-interaction, browser] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.count / tagui.title / tagui.text / tagui.timer + +# Responsibility + +Four simple read-only queries, all following the same +`send('dump () to rpa_python.txt'); return _tagui_output()` shape: + +- `count(element_identifier)` — number of elements matching the + identifier (requires `init(chrome_browser=True)`; returns `0` without + erroring if not started or no identifier given). +- `title()` — the current page's `` (requires + `init(chrome_browser=True)`). +- `text()` — the current page's visible text content (requires + `init(chrome_browser=True)`). +- `timer()` — elapsed seconds of the current TagUI flow, as a float; the + only one of the four that does **not** require `chrome_browser`. + +# Public Interface + +```python +count(element_identifier=None) # -> int +title() # -> str +text() # -> str +timer() # -> float +``` + +# Dependencies + +- [tagui.send](send.md), `_tagui_output()` from [tagui](../tagui.md). + +# Used By + +Standalone queries; not depended on by other documented functions. + +# Usage Example + +```python +r.url('https://example.com') +print(r.title(), r.count('//a')) +elapsed = r.timer() +``` diff --git a/docs/okf/tagui/string-utility.md b/docs/okf/tagui/string-utility.md new file mode 100644 index 0000000..3e630cb --- /dev/null +++ b/docs/okf/tagui/string-utility.md @@ -0,0 +1,49 @@ +--- +type: Function +title: tagui.get_text / tagui.del_chars +description: Pure string helpers with no TagUI/process interaction — substring extraction between two delimiters, and character stripping. +resource: tagui.py#L1862 +tags: [rpa, tagui, string-utility] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.get_text / tagui.del_chars + +# Responsibility + +Two pure, self-contained string functions with no dependency on +`init()`, `send()`, or any TagUI process state — usable standalone for +post-processing whatever [`read()`](read-snap.md)/[`dom()`](dom-run.md) +returned. + +- `get_text(source_text, left, right, count=1)` — returns the (stripped) + substring between the `count`-th occurrence of `left` and the next + occurrence of `right` after it. Returns `''` if either delimiter isn't + found at the requested occurrence. +- `del_chars(source_text, characters)` — removes every character in + `characters` from `source_text` (iterates and calls `str.replace` per + character). + +# Public Interface + +```python +get_text(source_text=None, left=None, right=None, count=1) # -> str +del_chars(source_text=None, characters=None) # -> str +``` + +# Dependencies + +None — pure string operations, no imports beyond built-ins. + +# Used By + +Standalone utilities; not called elsewhere in this module, intended for +use in caller scripts to post-process scraped text. + +# Usage Example + +```python +html = r.read('page') +price = r.get_text(html, '$', '<', count=1) +clean = r.del_chars('a-b-c', '-') # -> 'abc' +``` diff --git a/docs/okf/tagui/table-upload-bin.md b/docs/okf/tagui/table-upload-bin.md new file mode 100644 index 0000000..e74f5b8 --- /dev/null +++ b/docs/okf/tagui/table-upload-bin.md @@ -0,0 +1,66 @@ +--- +type: Function +title: tagui.table / tagui.upload / tagui.bin +description: Export an HTML table to CSV, upload a file through a file-input element, or upload a file to a paste/share service (deprecated) and return its link. +resource: tagui.py#L1399 +tags: [rpa, tagui, ui-interaction, deprecated] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.table / tagui.upload / tagui.bin + +# Responsibility + +- `table(element_identifier, filename_to_save)`: exports an HTML + `<table>` element to a CSV file. Requires both arguments non-empty, + checks [`exist()`](exist-present.md), then sends + `table <id> to <filename>` via [`send()`](send.md). +- `upload(element_identifier, filename_to_upload)`: uploads a local file + through a file-input UI element. Same guard pattern, sends + `upload <id> as <filename>`. +- `bin(file_to_bin, password, server)`: **deprecated** (per the project + README) — drives a full browser flow against a hardcoded third-party + paste service (`https://tebel.org/bin/` by default): saves the current + URL, navigates to `server`, verifies a `#message` element exists (else + errors "cannot connect to"), types the filename and optional password + into the form, clicks attach/upload/send, [`upload()`](#)s the actual + file, reads back the resulting share link from `#pastelink a`'s `href` + attribute, restores the original URL, and returns the link (or `''` on + failure). + +# Public Interface + +```python +table(element_identifier=None, filename_to_save=None) # returns True/False +upload(element_identifier=None, filename_to_upload=None) # returns True/False +bin(file_to_bin=None, password=None, server='https://tebel.org/bin/') # returns share URL or '' +``` + +# Dependencies + +- [tagui.exist-present](exist-present.md), [tagui.send](send.md) — used + by all three. +- `bin()` additionally calls [tagui.url](url.md), and reuses `upload()`, + [click family](click-family.md)'s `click()`, and + [type/select](type-select.md)'s `type()` internally to drive its + browser flow, plus [read/snap](read-snap.md)'s `read()` to fetch the + resulting link. + +# Used By + +Standalone calls; `bin()`'s internal reuse of `click`/`type`/`upload`/ +`read`/`url` is its only cross-function dependency in this module. + +# Usage Example + +```python +r.table('//table[@id="results"]', 'results.csv') +r.upload('#file-input', '/path/to/file.pdf') +``` + +# Notes + +- `bin()` is explicitly called out as deprecated in the project's + README — it depends on a specific external service + (`tebel.org/bin`) staying online and its DOM structure staying stable; + avoid it in new code. diff --git a/docs/okf/tagui/type-select.md b/docs/okf/tagui/type-select.md new file mode 100644 index 0000000..5a793c7 --- /dev/null +++ b/docs/okf/tagui/type-select.md @@ -0,0 +1,69 @@ +--- +type: Function +title: tagui.type / tagui.select +description: Type text into a UI element/coordinate, or select an option in a dropdown/select box. +resource: tagui.py#L1098 +tags: [rpa, tagui, ui-interaction] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.type / tagui.select + +# Responsibility + +`type()` enters `text_to_type` into `element_identifier`; `select()` +picks `option_value` in `element_identifier`. Both require `init()`, a +non-empty target, and a non-empty value, check +[`exist()`](exist-present.md), then delegate to [`send()`](send.md) +sending `type <id> as <text>` / `select <id> as <value>`. + +- `type()`'s `(x, y)` overload: pass `test_coordinate` as an int — it's + actually detected on `text_to_type` being an int + (`isinstance(text_to_type, int)`), which then means + `element_identifier` is treated as x, `text_to_type` as y, and the + *third* positional argument (named `test_coordinate` in the signature) + becomes the actual text to type. Concretely: + `type(600, 300, 'Mario')` → clicks/types at `(600, 300)` the text + `'Mario'`. +- `select()`'s coordinate overload similarly repurposes + `option_value`/`test_coordinate1`/`test_coordinate2` as x1/x2/y2 — + `select(600, 300, 600, 400)` selects the dropdown at `(600,300)` to the + option represented by `(600,400)`. +- `select()` additionally rejects `'page.png'`/`'page.bmp'` for either + argument (they're not valid selectable identifiers), and separately + requires `init(visual_automation=True)` if either argument is a + `.png`/`.bmp` image identifier. + +# Public Interface + +```python +type(element_identifier=None, text_to_type=None, test_coordinate=None) +select(element_identifier=None, option_value=None, + test_coordinate1=None, test_coordinate2=None) +``` + +# Dependencies + +- [tagui.exist-present](exist-present.md), [tagui.send](send.md) — same + guard/dispatch pattern as the [click family](click-family.md). +- Uses `_esq()`/`_sdq()` from [tagui](../tagui.md) to escape the text/ + option value and identifier respectively before sending. + +# Used By + +- [sample](../sample.md) — `r.type('ybar-sbq', 'github')`. + +# Usage Example + +```python +r.type('ybar-sbq', 'github') # '[enter]' / '[clear]' are special values +r.type(600, 300, 'Mario') # by coordinate +r.select('#country', 'Singapore') +``` + +# Notes + +- `'[enter]'` and `'[clear]'` are documented (in `sample.py`'s comments) + as special values for `text_to_type` — enter key and clear-field, + respectively — interpreted by TagUI's own `type` step, not by this + Python wrapper. diff --git a/docs/okf/tagui/url.md b/docs/okf/tagui/url.md new file mode 100644 index 0000000..44678b0 --- /dev/null +++ b/docs/okf/tagui/url.md @@ -0,0 +1,48 @@ +--- +type: Function +title: tagui.url +description: Navigate the browser to a webpage URL, or (called with no argument) return the current URL. +resource: tagui.py#L985 +tags: [rpa, tagui, ui-interaction, browser] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.url + +# Responsibility + +Dual-purpose function distinguished purely by whether an argument was +passed. Requires `init(chrome_browser=True)` (the default). With a +`webpage_url` argument: auto-prepends `https://` if the string starts +with `www.`, requires the (possibly-rewritten) URL to start with +`http://`/`https://`, then sends it via [`send()`](send.md). With no +argument: sends `dump url() to rpa_python.txt` and returns the current +URL read back from that file. + +# Public Interface + +```python +url(webpage_url=None) # navigates if given, else returns current URL (str) +``` + +# Dependencies + +- [tagui.send](send.md) — both to navigate and to query the current URL. +- Uses `_started()`, `_chrome()`, `_esq()`, `_tagui_output()` from + [tagui](../tagui.md). + +# Used By + +- [sample](../sample.md) — `r.url('https://ca.yahoo.com')`, then later + `r.url('https://duckduckgo.com')`. +- [tagui.table-upload-bin](table-upload-bin.md) — `bin()` saves and + restores the current URL around its upload flow using + `url()`/`url(original_url)`. + +# Usage Example + +```python +r.url('https://ca.yahoo.com') # navigate +r.url('www.example.com') # 'www.' auto-upgraded to 'https://' +current = r.url() # query current URL +``` diff --git a/docs/okf/tagui/visual-input.md b/docs/okf/tagui/visual-input.md new file mode 100644 index 0000000..92bd3af --- /dev/null +++ b/docs/okf/tagui/visual-input.md @@ -0,0 +1,51 @@ +--- +type: Function +title: tagui.keyboard / tagui.mouse / tagui.vision +description: Send keyboard key combinations, mouse button down/up events, or raw SikuliX "vision" commands — all require visual automation mode. +resource: tagui.py#L1327 +tags: [rpa, tagui, visual-automation] +timestamp: 2026-07-22T09:58:59Z +--- + +# tagui.keyboard / tagui.mouse / tagui.vision + +# Responsibility + +Three thin dispatchers that all share the same guard: require `init()`, +require a non-empty argument, and specifically require +`init(visual_automation=True)` (checked via `_visual()`) — these +capabilities only work through SikuliX, TagUI's visual-automation engine, +not the default Chrome-only mode. + +- `keyboard(keys_and_modifiers)`: sends `keyboard <keys>` — TagUI/SikuliX + key-combination syntax (e.g. modifier+key sequences). +- `mouse(mouse_action)`: only accepts the literal strings `'down'` or + `'up'` (case-insensitive); sends `mouse down`/`mouse up`. +- `vision(command_to_run)`: sends `vision <command>` verbatim — a direct + escape hatch into SikuliX vision commands not otherwise exposed. + +# Public Interface + +```python +keyboard(keys_and_modifiers=None) # returns True/False +mouse(mouse_action=None) # 'down' or 'up'; returns True/False +vision(command_to_run=None) # returns True/False +``` + +# Dependencies + +- [tagui.send](send.md) — all three just forward to `send()`. +- Uses `_visual()`, `_esq()` from [tagui](../tagui.md). + +# Used By + +Standalone calls, only usable after `init(visual_automation=True)`. + +# Usage Example + +```python +r.init(visual_automation=True) +r.mouse('down'); r.mouse('up') +r.keyboard('[ctrl]a') +r.vision('click Submit.png') +```