Skip to main content

tamash-selenium (Python)

PyPI CI Python License: Apache 2.0

Plug-and-play self-healing for Selenium + Python. Wrap your WebDriver once and every find_element through it — in Page Objects, helper/util layers, inside a WebDriverWait — recovers automatically when a locator breaks. Nothing else changes.

from selenium import webdriver
from tamash_selenium import SelfHealingDriver

driver = SelfHealingDriver.wrap(webdriver.Chrome())

That's the whole integration.

Also available for Selenium Java (com.vibetestq.qtpsudhakar:tamash-selenium on Maven Central) and for Playwright — TypeScript & Python (tamash-playwright). Same idea, one package per ecosystem.

Why you need this

Websites change. A button gets renamed or moved and your test can't find it anymore — even though the app works fine for real users. Normally that's a broken test.

tamash-selenium fixes it: when find_element can't find an element, it locates it on the live page — with a rule-based matcher (default, no key, no network) or an AI model — and retries. If it can't, the test fails exactly as it would have without the package. Healing never masks a real failure.

Step 1: Install

pip install tamash-selenium

Pulls in Selenium 4 (which provisions the browser drivers itself since 4.6). Requires Python 3.9+.

Optional AI-provider extras:

pip install 'tamash-selenium[anthropic]'              # HEALER_PROVIDER=anthropic | claude-subscription
pip install 'tamash-selenium[copilot-subscription]'   # Python 3.11+ ; also needs the `copilot` CLI

The openai / gemini / ollama / ollama-local providers need nothing extra.

Worked examples — every test style and every healing scenario, with locators broken on purpose — live in tamash-selenium-python-sample.

Step 2: Wrap the driver

Wherever you create the driver — a fixture, a DriverFactory, a setUp:

from tamash_selenium import SelfHealingDriver

driver = SelfHealingDriver.wrap(my_driver)   # Remote / Grid / cloud all fine

Everything downstream is now healing-aware — plain find_element, Page Objects, waits.

Wrapping also pins Selenium's implicit wait to 0 (mixing implicit + explicit waits is an anti-pattern, and a high implicit wait delays healing) — set TAMASH_KEEP_IMPLICIT_WAIT=true to keep yours.

Or let an integration own the lifecycle

Framework How
pytest The plugin auto-loads. Use the driver (or tamash_driver) fixture — or wrap your own driver fixture with SelfHealingDriver.wrap.
pytest-bdd Same — scenarios are pytest tests; use tamash_driver in step functions.
Behave Delegate the four environment.py hooks to tamash_selenium.integrations.behave (see its docstring).
unittest class LoginTest(TamashSeleniumTestCase): ... — use self.driver.

Step 3 (optional): connect an AI provider

With no configuration, healing uses the rule-based tamash provider — no key, no network, no tokens; it text-matches the element's decoded name against the page's accessibility tree and never guesses. Good for well-named suites.

For stronger healing, set a provider in a .env at your project root (or real env vars, or a [tool.tamash-selenium] table in pyproject.toml):

Provider Auth
ollama OLLAMA_API_KEY + OLLAMA_MODEL (Ollama Cloud — free key)
ollama-local OLLAMA_LOCAL_MODEL (+ OLLAMA_LOCAL_BASE_URL; key optional)
openai OPENAI_API_KEY + OPENAI_MODEL
anthropic ANTHROPIC_API_KEY + ANTHROPIC_MODEL (needs the [anthropic] extra)
gemini GEMINI_API_KEY + GEMINI_MODEL
claude-subscription CLAUDE_CODE_OAUTH_TOKEN (claude setup-token) — bills your Claude subscription
copilot-subscription the [copilot-subscription] extra + the copilot CLI signed in
tamash nothing — the default
HEALER_PROVIDER=ollama
OLLAMA_MODEL=gpt-oss:120b
OLLAMA_API_KEY=paste_your_key_here

HEALER_ENABLED=false turns healing off entirely (e.g. per-CI-run).

Step 4: Check your setup

tamash-selenium doctor

Provider connectivity (a live call), the implicit-wait note, and a scan for brittle locators bound to non-descriptive names.

How it heals

When find_element can't find its element:

  1. Cache — a selector already healed this run for that locator (any caller, including a wait's next poll) is reused instantly.
  2. DOM snapshot — a JS accessibility tree of the page is captured; the provider is shown the relevant slice (matched to the element's decoded name), or the full tree.
  3. ref + durable derivation — the provider picks the element; a stable locator is derived for it (By.IDBy.NAME → a data-testid / aria-label CSS → link text → a structural XPath), verified against the live element before it's trusted.
  4. Action recovery (opt-in, HEALER_ACTION_RECOVERY_ENABLED=true) — scroll / JS-click / wait / dispatch when the element is found but the action is blocked.

Every heal logs [self-healer] … -> HEALED [provider=…, suggested="(By.ID, \"username\")"].

Writing locators the healer can work with

(By.ID, ...) / (By.NAME, ...) carry their own meaning. A raw (By.CSS_SELECTOR, ...) / (By.XPATH, ...) doesn't — bind it to a descriptive variable / attribute and the healer decodes the name: txt_employee_id → "Employee Id (textbox)", submit_button → "Submit (button)" (deterministic, no AI). Decoding works when the locator is on the same line as its find_element call, or is a page-object attribute the call references by name.

Explicit hint — for keyword-driven suites or heavy indirection:

from tamash_selenium import hint

def click(locator, name):
    with hint(name):
        driver.find_element(*locator).click()

What gets healed (and what doesn't)

Intercepted on WebElement: click, send_keys, clear, submit, and the read methods (get_attribute, get_dom_attribute, get_dom_property, get_property, value_of_css_property, is_displayed, is_enabled, is_selected). Plus find_element / find_elements on the driver and on elements.

Not touched: the ActionChains API, WebElement.text (a Python property — can't be intercepted per-instance; use get_attribute("textContent") if you need it healed), and find_elements (never healed — use driver.find_elements(by, value) for absence checks).

Assert-absent is never healed: pytest.raises(NoSuchElementException), EC.invisibility_of_element_located, EC.staleness_of, or a helper whose name contains absent / not_present / gone. HEALER_ASSERTIONS=strict also refuses to heal a locator resolved inside an assertion; HEALER_ASSERTIONS=warn heals but prints an end-of-run summary.

Making a heal permanent: apply-heals

A runtime heal fixes the current run; apply-heals writes it into source:

tamash-selenium apply-heals --dry-run   # preview
tamash-selenium apply-heals             # apply (prompts first)
#  (By.CSS_SELECTOR, "#old")   →  (By.ID, "username")
#  driver.find_element(By.CSS_SELECTOR, "#old")  →  driver.find_element(By.ID, "username")

It rewrites an inline find_element(By.*, "…") call or a LOGIN = (By.*, "…") tuple constant (via the heal log's recorded declaration line), writes Markdown + JSON reports under .tamash-selenium/, and generates verify_heals.py that re-runs exactly the affected pytest node ids with HEALER_ENABLED=false.

HTML step report

pytest --tamash-report=report.html          # pytest
TAMASH_REPORT=report.html python my_script.py   # plain / Behave / unittest

Per test: step timeline, which steps healed (recovered selector, provider, token cost), the DOM snapshot on an unrecovered failure. Zero overhead when unset.

Agent skill

tamash-selenium init-skill

Copies a coding-agent skill (SKILL.md + references/) into .claude/skills/tamash-selenium/ and .agents/skills/tamash-selenium/ that drives the local run → review → apply-heals → verify → land loop.

Environment variables

Variable Default Purpose
HEALER_ENABLED true Master switch. false / 0 turns healing off.
HEALER_PROVIDER tamash ollama | ollama-local | openai | anthropic | gemini | claude-subscription | copilot-subscription | tamash.
HEALER_ASSERTIONS heal heal | warn | strict.
HEALER_ACTION_RECOVERY_ENABLED false Opt-in scroll / force / wait / dispatch recovery.
HEALER_PARALLEL false Race the scoped + full-snapshot provider calls concurrently.
TAMASH_KEEP_IMPLICIT_WAIT false true keeps your implicit wait.
TAMASH_BROWSER chrome chrome | firefox | edge | safari (integrations only).
HEADLESS true false runs headed (integrations only).
TAMASH_REUSE_DRIVER false One driver per class / feature instead of per test.
TAMASH_ACTION_TIMEOUT_MS 20000 Bounds the healer's own snapshot / JS calls.
TAMASH_REPORT unset Output path for the HTML step report.
TAMASH_DEBUG unset Print DOM-snapshot capture diagnostics.
OPENAI_API_KEY / OPENAI_MODEL / OPENAI_BASE_URL OpenAI.
ANTHROPIC_API_KEY / ANTHROPIC_MODEL Anthropic.
GEMINI_API_KEY / GEMINI_MODEL / GEMINI_THINKING — / — / off Gemini.
OLLAMA_API_KEY / OLLAMA_MODEL / OLLAMA_BASE_URL — / — / https://ollama.com Ollama Cloud.
OLLAMA_LOCAL_MODEL / OLLAMA_LOCAL_BASE_URL / OLLAMA_LOCAL_API_KEY — / http://localhost:11434 / — Self-hosted Ollama.
CLAUDE_CODE_OAUTH_TOKEN / CLAUDE_SUBSCRIPTION_MODEL — / claude-haiku-4-5 claude-subscription.
COPILOT_SUBSCRIPTION_MODEL mai-code-1-flash-picker copilot-subscription.

What's tested

Every push runs in CI:

  • Python 3.9 / 3.11 / 3.13 on Linux, plus 3.11 on Windows
  • Browsers — a broken locator heals on Chrome, Firefox and Edge
  • Providers — a real end-to-end heal per provider (informational jobs, gated on the key being configured): openai, anthropic, gemini, ollama, ollama-local (CI starts a real ollama serve), claude-subscription, copilot-subscription
  • CLIdoctor, apply-heals (AST rewrite of inline calls and tuple constants), init-skill
  • Integrations — pytest plugin, pytest-bdd, Behave, unittest, pytest-selenium interop, plain wrap()
  • tamash-selenium-python-sample runs all of the above as broken-locator scenarios against bundled fixtures and a live OrangeHRM app

License

Apache License, Version 2.0.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tamash_selenium-0.1.1.tar.gz (96.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tamash_selenium-0.1.1-py3-none-any.whl (108.9 kB view details)

Uploaded Python 3

File details

Details for the file tamash_selenium-0.1.1.tar.gz.

File metadata

  • Download URL: tamash_selenium-0.1.1.tar.gz
  • Upload date:
  • Size: 96.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.14.7

File hashes

Hashes for tamash_selenium-0.1.1.tar.gz
Algorithm Hash digest
SHA256 098aa445a149a4f4695c9c6bbd0043813193ad87fa6c2f972b988a1e62fbfae6
MD5 4190f04d70380088f8f96075326f0612
BLAKE2b-256 eea39cb2ddf6223478245eb9c84a9e3c27246e28c7a6cbf2baf1612d5a9ec744

See more details on using hashes here.

File details

Details for the file tamash_selenium-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for tamash_selenium-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5fe1f128b4fb933ccab09e616cc5df180f4820f6bb5568966a67b190e66c4c10
MD5 ab7b003f6700da7ccb01846e8573f59a
BLAKE2b-256 b4e65b142a565d110f28319edb0327cbe32da6ea18ab7d656053e197b0b5a10d

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 files

0.1.0

2 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page