diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 87749ca..cdfdb46 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -128,11 +128,11 @@ jobs: # ── Linux x86_64 ── - os: ubuntu-latest target: x86_64-unknown-linux-gnu - manylinux: auto + manylinux: "2_28" # ── Linux aarch64 ── - os: ubuntu-latest target: aarch64-unknown-linux-gnu - manylinux: auto + manylinux: "2_28" # ── macOS x86_64 (Intel, cross-compiled on ARM) ── - os: macos-14 target: x86_64-apple-darwin @@ -203,8 +203,10 @@ jobs: - name: Publish to PyPI uses: pypa/gh-action-pypi-publish@release/v1 + with: + verbose: true # Uses Trusted Publisher (OIDC) — no API token needed. - # Register at: https://pypi.org/manage/project/playleft/settings/publishing/ + # Register at: https://pypi.org/manage/project/playwleft/settings/publishing/ # ── 6. Create GitHub Release ────────────────────────────── release: @@ -238,10 +240,10 @@ jobs: **Rust-powered release** — native compiled extensions for maximum performance. - Published to [PyPI](https://pypi.org/project/playleft/${{ needs.check-version.outputs.new_version }}/). + Published to [PyPI](https://pypi.org/project/playwleft/${{ needs.check-version.outputs.new_version }}/). ```bash - pip install playleft==${{ needs.check-version.outputs.new_version }} + pip install playwleft==${{ needs.check-version.outputs.new_version }} ``` ### Platforms diff --git a/README.md b/README.md index a84c648..251add7 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ of visual tooling. ```python import asyncio -from playleft import PlaywLeft +from playwleft import PlaywLeft async def main(): async with PlaywLeft() as pw: @@ -76,7 +76,7 @@ asyncio.run(main()) ## Installation ```bash -pip install playleft +pip install playwleft ``` ## Class Hierarchy diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index 2d5e5fe..d8409bb 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -15,11 +15,11 @@ tracing-subscriber = { workspace = true } futures-util = { workspace = true } url = { workspace = true } -# WebSocket client for CDP (rustls for cross-platform builds) +# WebSocket client for CDP (rustls = pure Rust, no system dependencies) tokio-tungstenite = { version = "0.26", features = ["rustls-tls-webpki-roots"] } # HTTP client for browser discovery -reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls"] } +reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls-webpki-roots"] } # Process management which = "7" diff --git a/examples/agent_workflow.py b/examples/agent_workflow.py index 259eed3..0ddb0b3 100644 --- a/examples/agent_workflow.py +++ b/examples/agent_workflow.py @@ -2,7 +2,7 @@ import asyncio import json -from playleft import PlaywLeft +from playwleft import PlaywLeft async def search_and_extract(query: str) -> dict: diff --git a/examples/basic_navigation.py b/examples/basic_navigation.py index d051539..9b27dfa 100644 --- a/examples/basic_navigation.py +++ b/examples/basic_navigation.py @@ -1,7 +1,7 @@ """Basic navigation example for playwLeft.""" import asyncio -from playleft import PlaywLeft +from playwleft import PlaywLeft async def main(): diff --git a/examples/web_scraping.py b/examples/web_scraping.py index 84217fd..b5d0373 100644 --- a/examples/web_scraping.py +++ b/examples/web_scraping.py @@ -2,7 +2,7 @@ import asyncio import json -from playleft import PlaywLeft +from playwleft import PlaywLeft async def main(): diff --git a/pyproject.toml b/pyproject.toml index 3ebdb89..11a163c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ["maturin>=1.7,<2.0"] build-backend = "maturin" [project] -name = "playleft" +name = "playwleft" version = "0.1.0" description = "Agent-first browser automation toolkit — Playwright alternative built in Rust" readme = "README.md" @@ -46,7 +46,7 @@ Issues = "https://github.com/CocoRoF/playwLeft/issues" [tool.maturin] manifest-path = "crates/python/Cargo.toml" -module-name = "playleft._core" +module-name = "playwleft._core" python-source = "python" features = ["pyo3/extension-module"] diff --git a/python/playleft/__init__.py b/python/playwleft/__init__.py similarity index 91% rename from python/playleft/__init__.py rename to python/playwleft/__init__.py index b645fe4..04b1d1c 100644 --- a/python/playleft/__init__.py +++ b/python/playwleft/__init__.py @@ -6,7 +6,7 @@ Usage: import asyncio - from playleft import PlaywLeft + from playwleft import PlaywLeft async def main(): pw = PlaywLeft() @@ -20,7 +20,7 @@ async def main(): asyncio.run(main()) """ -from playleft._core import ( +from playwleft._core import ( PlaywLeft, BrowserType, Browser, diff --git a/python/playleft/_core.pdb b/python/playwleft/_core.pdb similarity index 100% rename from python/playleft/_core.pdb rename to python/playwleft/_core.pdb diff --git a/python/playleft/_core.pyi b/python/playwleft/_core.pyi similarity index 100% rename from python/playleft/_core.pyi rename to python/playwleft/_core.pyi diff --git a/python/playleft/playleft.pdb b/python/playwleft/playleft.pdb similarity index 100% rename from python/playleft/playleft.pdb rename to python/playwleft/playleft.pdb diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_smoke.py b/tests/test_smoke.py new file mode 100644 index 0000000..28b6acb --- /dev/null +++ b/tests/test_smoke.py @@ -0,0 +1,39 @@ +"""Smoke tests — verify the package installs and imports correctly. + +These tests don't require a browser and should pass in any CI environment. +""" + +import playwleft + + +def test_version_exists(): + """__version__ should be a non-empty string.""" + assert isinstance(playwleft.__version__, str) + assert len(playwleft.__version__) > 0 + + +def test_version_format(): + """__version__ should look like semver (x.y.z).""" + parts = playwleft.__version__.split(".") + assert len(parts) == 3 + for part in parts: + assert part.isdigit() + + +def test_all_public_classes_importable(): + """Every name in __all__ should be importable.""" + for name in playwleft.__all__: + assert hasattr(playwleft, name), f"{name} listed in __all__ but not found" + + +def test_playwleft_instantiation(): + """PlaywLeft() should create an instance without errors.""" + pw = playwleft.PlaywLeft() + assert pw is not None + + +def test_chromium_browser_type(): + """PlaywLeft().chromium() should return a BrowserType.""" + pw = playwleft.PlaywLeft() + bt = pw.chromium() + assert isinstance(bt, playwleft.BrowserType)