crosslocator
Define a UI selector once. Resolve it on every platform.
Cross-platform test automation means maintaining the same element for Android,
iOS, iPadOS, Windows and the web. Most teams end up either duplicating selectors
or scattering if platform == ... branches through their page objects.
crosslocator lets you declare a selector once, per platform, and resolves
the right one at runtime — from pure Python (Appium), Robot Framework, or any
other framework. It only routes selector strings; it never wraps your driver.
from crosslocator import Locator
ADD_PATIENT = Locator(
android="accessibility_id=add_patient",
ios="add_patient",
windows='//Button[@Name="Add"]',
default="id=add",
)
ADD_PATIENT.for_platform("ios") # -> "add_patient"
Installation
pip install crosslocator
Zero runtime dependencies.
Why
- One source of truth per element — no duplicated selectors, no platform
if/else. - Framework-agnostic — Appium in plain Python, Robot Framework, or anything else.
- Sensible fallbacks — iPad inherits from iOS, and a shared
defaultcovers the rest. - Typed and dependency-free.
Quick start (Python)
from crosslocator import Locator, set_current_platform
ADD_PATIENT = Locator(
android="accessibility_id=add_patient",
ios="add_patient",
windows='//Button[@Name="Add"]',
)
set_current_platform("android") # usually done once, at session start
ADD_PATIENT.resolve() # -> "accessibility_id=add_patient"
Robot Framework
*** Settings ***
Library crosslocator.robot.CrossLocator
Variables locators.py # ADD_PATIENT defined as a Locator here
*** Test Cases ***
Open Add Patient
Set Current Platform android
${selector}= Resolve Locator ${ADD_PATIENT}
# -> pass ${selector} to AppiumLibrary / Browser as usual
How the platform is resolved
resolve() determines the current platform in this order:
- an explicit
set_current_platform(...) - the
CROSSLOCATOR_PLATFORMenvironment variable - a registered provider — typically an Appium session (see below)
Automatic platform detection (Appium)
Let crosslocator read the platform straight from a live Appium session, so you
never call set_current_platform by hand.
Python (Appium-Python-Client):
from crosslocator import use_appium
use_appium(driver) # your Appium webdriver
LOGIN_BUTTON.resolve() # platform detected from the session capabilities
Robot Framework (AppiumLibrary):
Open Application ${REMOTE_URL} platformName=Android ...
Use Appium Session
${selector}= Resolve Locator ${LOGIN_BUTTON}
iPad is detected from the session device name and resolves to iPad selectors (falling back to iOS when none are defined).
Fallback rules
ipad→ falls back toioswhen no iPad-specific selector is set- any platform → falls back to
default - nothing found →
LocatorNotFound
Examples
Runnable examples (no device needed) live in the examples/ folder —
a login screen resolved across Android, iOS, iPadOS and Windows, plus a Robot
Framework suite.
Roadmap
- v0.1: the core
Locatortype, platform resolution, Robot Framework keywords. - v0.2 (current): automatic platform detection from a live Appium session.
- Next: Playwright/Browser helpers, and declarative loading of whole screens from YAML/dict.
Issues and contributions are welcome.
License
MIT © 2026 Julien Becheny
Metadata
Release files for crosslocator 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| crosslocator-0.2.0.tar.gz | 8.8 kB | Without provenance | Details for crosslocator-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| crosslocator-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for crosslocator-0.2.0-py3-none-any.whl |
Total release size: 17.4 kB
Release files / crosslocator-0.2.0.tar.gz
| Download URL | crosslocator-0.2.0.tar.gz |
|---|---|
| Size | 8.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b8fe534088357caf956451af334c394756bcbb595e0adfa3658e1e9fbc83b858
|
|
BLAKE2b-256 checksum How to use checksums |
018fed37c5616a136d2cab390a9483e082fc4899e907c702a32d7c868c0b1501
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.7
|
Release files / crosslocator-0.2.0-py3-none-any.whl
| Download URL | crosslocator-0.2.0-py3-none-any.whl |
|---|---|
| Size | 8.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
d222c6a5ddbeabd984002548530b01ab74979779fa8e5d815db255ba0baae0d6
|
|
BLAKE2b-256 checksum How to use checksums |
ae6080b40b1351f09072a0f03774874c51f80c972efe5c84b7a9c05f73c04855
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.7
|
Security for crosslocator 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.