Metadata-Version: 2.4
Name: python-ai-locator
Version: 1.0.0
Summary: Python AI Locator for Playwright, Pytest, Selenium, Robot Framework, Etc.
Author-email: Jeorge Concepcion <jeorge.concepcion@gmail.com>
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: python-dotenv~=1.2.2
Requires-Dist: lxml~=6.1.1
Requires-Dist: langchain~=1.3.1
Requires-Dist: langchain-aws~=1.5.0
Requires-Dist: langchain-google-genai~=4.2.3
Requires-Dist: langchain-groq~=1.1.2
Requires-Dist: langchain-huggingface~=1.2.2
Requires-Dist: langchain-core~=1.4.0
Requires-Dist: langchain-anthropic~=1.4.3
Requires-Dist: langchain-classic~=1.0.7
Requires-Dist: pydantic~=2.13.4
Provides-Extra: dev
Requires-Dist: pytest~=9.0.3; extra == "dev"
Requires-Dist: playwright~=1.60.0; extra == "dev"
Requires-Dist: pytest-playwright~=0.8.0; extra == "dev"
Requires-Dist: pytest-html~=4.2.0; extra == "dev"
Requires-Dist: selenium~=4.44.0; extra == "dev"
Requires-Dist: robotframework-seleniumlibrary~=6.9.0; extra == "dev"
Dynamic: license-file

# Plugin Setup
This guide covers the minimum setup required to have the plugin `python-ai-locator` ready for your test automation.

---
## Prerequisites (for new test project)
- Python 3.10+
- Python Manager (e.g. pyenv): recommended
- Virtual Environment: recommended
- IDE (e.g. PyCharm)
- Git Project
## Prerequisites (for existing test project)
- Python 3.10+
- IDE (e.g. PyCharm)
- Existing Git Project (using one of the following: Pytest, Playwright, Selenium, Robot Framework - SeleniumLibrary)
---
## Getting Started
Open your Git Project in your IDE.

In the IDE terminal, activate your Virtual Environment and perform all the instructions below.

---
### 1. Install Plugin `python-ai-locator`
Before you install the package, ensure that you are in the root directory of your Git Project.
```bash
pip install python-ai-locator
```
-OR-
```bash
pip install git+ssh://git@github.com/je0rge/python-ai-locator.git
```
-OR-

To install a specific version:
```bash
pip install git+ssh://git@github.com/je0rge/python-ai-locator.git@v0.1.0
```
Available Tools:

To list the supported LLMs:
```bash
supported-llm
```
To get the LLM info:
```bash
supported-llm --info <supported llm>
```
To create .env for the chosen LLM:
```bash
create-dot-env --llm <supported llm>
```
To list the supported Automation Tools:
```bash
supported-tool
```
To get info on the Tool:
```bash
supported-tool --info <supported tool>
```
To create sample test file for the chosen Automation Tool:
```bash
create-sample-test --tool <supported tool>
```
---
### 2. Create `.env`
Choose one below and AI will use this to instantiate its Agent.

Note:
To get your free or trial api key or token, create an account with `google.com`, `groq.com` and `huggingface.co`.
```env
LLM="BEDROCK"
MODEL_ID="<aws bedrock model id e.g. us.anthropic.claude-haiku-4-5-20251001-v1:0>"
REGION_NAME="<region> e.g. us-east-1>"
TEMPERATURE=<0.7 or set your own>
AWS_ACCESS_KEY_ID="<access key id>"
AWS_SECRET_ACCESS_KEY="<secret access key>"
AWS_SESSION_TOKEN="<session token>"
INPUT_COST_PER_1M_TOKENS=0
OUTPUT_COST_PER_1M_TOKENS=0
```
```env
LLM="GEMINI"
GOOGLE_API_KEY="<your_free_gemini_api_key_here>"
MODEL_ID="<google gemini model id e.g. gemini-2.5-flash>"
TEMPERATURE=<0.7 or set your own>
INPUT_COST_PER_1M_TOKENS=0
OUTPUT_COST_PER_1M_TOKENS=0
```
```env
LLM="GROQ"
GROQ_API_KEY="<your_free_groq_api_key_here>"
MODEL_ID="<groq model id e.g. llama-3.3-70b-versatile>"
TEMPERATURE=<0.7 or set your own>
INPUT_COST_PER_1M_TOKENS=0
OUTPUT_COST_PER_1M_TOKENS=0
```
```env
LLM="HUGGINGFACE"
HF_TOKEN="<your_free_hugging_face_api_token_here>"
MODEL_ID="<hugging face supported repo id e.g. Qwen/Qwen2.5-3B-Instruct:featherless-ai>"
TEMPERATURE=<0.7 or set your own>
INPUT_COST_PER_1M_TOKENS=0
OUTPUT_COST_PER_1M_TOKENS=0
```
---
### 3. sample tests
playwright - sample login test:
```python
import pytest
from playwright.sync_api import Page, expect

# to import the plugin
from python_ai_locator import PlaywrightAiLocator
###

class TestLogin:
    def test_login(self, page):
        self.page = page
        # to instantiate the plugin
        self.ai = PlaywrightAiLocator(page)
        ###

        # to provide context info to the plugin
        test_info = {"file_name": "test_playwright_ai_locator.py", "test_case": "test_login"}
        self.ai.set_test_info(test_info)
        self.ai.set_save_locators(True)
        self.ai.set_debug_mode(True)
        ###

        self.page.goto("https://example.com")
        expect(self.page).to_have_title('Example')
        self.page.locator(self.ai.locator("Username Input Field")).fill("user123")
        self.page.locator(self.ai.locator("Password Input Field")).fill("pass123")
        self.page.locator(self.ai.locator("Login Button")).click()
        expect(self.page).to_have_title("Dashboard")
```
selenium - sample login test:
```python
import unittest
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# to import the plugin
from python_ai_locator import SeleniumAiLocator
###

class TestLogin(unittest.TestCase):
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()

        # to instantiate the plugin
        self.ai = SeleniumAiLocator(self.driver)
        ###

    def test_login(self):
        # to provide context info to the plugin
        test_info = {"file_name": "test_selenium_ai_locator.py", "test_case": "test_login"}
        self.ai.set_test_info(test_info)
        self.ai.set_save_locators(True)
        self.ai.set_debug_mode(True)
        ###

        self.driver.get("https://example.com")
        WebDriverWait(self.driver, 10).until(EC.title_contains("Example"))
        assert "Example" in self.driver.title

        username_input = WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.XPATH, self.ai.locator("Username Input Field")))
        )
        username_input.send_keys("user123")

        password_input = WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.XPATH, self.ai.locator("Password Input Field")))
        )
        password_input.send_keys("pass123")

        login_button = WebDriverWait(self.driver, 10).until(
            EC.presence_of_element_located((By.XPATH, self.ai.locator("Login Button")))
        )
        login_button.click()

        WebDriverWait(self.driver, 10).until(EC.title_contains("Dashboard"))
        assert "Dashboard" in self.driver.title

    def tearDown(self):
        self.driver.quit()

if __name__ == "__main__":
    unittest.main()
```
robot framework - sample login test:
```robot
*** Settings ***
Library    SeleniumLibrary

# to import the plugin
Library    python_ai_locator.RobotAiLocator
###

*** Test Cases ***
Test Login
    [Tags]    robot    selib
    # to provide context info to the plugin
    ${test_info}=    Create Dictionary    file_name=test_robot_ai_locator.robot    test_case=Test Login
    Set Test Info        ${test_info}
    Set Save Locators    ${TRUE}
    Set Debug Mode       ${TRUE}

    Open Browser    https://example.com    chrome
    Maximize Browser Window

    # to provide the webdriver to the plugin
    ${selib}=         Get Library Instance        SeleniumLibrary    
    Set Driver        ${selib.driver}
    
    Title Should Be    Example
    
    ${username_input}=    Locator    Username Input Field
    Wait Until Element Is Visible    ${username_input}    timeout=10s
    Input Text                       ${username_input}    user123
    
    ${password_input}=    Locator    Password Input Field
    Wait Until Element Is Visible    ${password_input}    timeout=10s
    Input Text                       ${password_input}    pass123

    ${login_button}=       Locator    Login Button
    Wait Until Element Is Enabled    ${login_button}      timeout=10s
    Click Element                    ${login_button}

    Title Should Be    Dashboard

    [Teardown]    Close Browser
```
generic plugin in playwright - sample login test:
```python
import pytest
from playwright.sync_api import Page, expect

# to import the plugin
from python_ai_locator import AiLocator
###

# define the fn_get_browser_html function with self as the first argument
def get_browser_html(self, page: Page) -> str:
    html = page.content()
    return html

# define the fn_is_element_visible function with self as the first argument
def is_element_visible(self, page: Page, xpath: str) -> bool:
    visible = page.locator(xpath).is_visible()
    return visible

class TestLogin:
    def test_login(self, page):
        self.page = page
        
        # to instantiate the plugin
        self.ai = AiLocator(page)
        ###

        # to provide context info to the plugin
        test_info = {"file_name": "test_generic_ai_locator.py", "test_case": "test_login"}
        self.ai.set_test_info(test_info)
        self.ai.set_save_locators(True)
        self.ai.set_debug_mode(True)
        ###

        self.page.goto("https://example.com")
        
        # to register the functions after browser loads physically
        self.ai.register_fn_get_browser_html(get_browser_html)
        self.ai.register_fn_is_element_visible(is_element_visible)
        ###
        
        expect(self.page).to_have_title('Example')
        self.page.locator(self.ai.locator("Username Input Field")).fill("user123")
        self.page.locator(self.ai.locator("Password Input Field")).fill("pass123")
        self.page.locator(self.ai.locator("Login Button")).click()
        expect(self.page).to_have_title("Dashboard")
```
---
### 4. Auto-created by test runs: `locators/<test_module>/.env.<test_case>`
Test runs automatically create this files per test case to save the locators that was used by the test provided that the flag was set to True.

Pytest, Playwright and Selenium:
```python
self.ai.set_save_locators(True)
```

Robot Framework:
```robot
Set Save Locators    ${TRUE}
```

Note: When there are locators which have dynamic values, you may update this file and put `ai_locator` as value to have the AI to always generate the locator on every run.

sample content:
```env
username__input__field='//input[@name=\'username\']'
password__input__field='//input[@name=\'password\']'
login__button='//button[@name=\'submit\']'
```
---
