{"id":47784517,"url":"https://github.com/itential/asyncgateway","last_synced_at":"2026-04-03T14:15:39.892Z","repository":{"id":343081672,"uuid":"1176203620","full_name":"itential/asyncgateway","owner":"itential","description":"A Python async client for Itential Automation Gateway","archived":false,"fork":false,"pushed_at":"2026-03-08T19:21:58.000Z","size":191,"stargazers_count":0,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-08T23:32:01.982Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/itential.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":"CODEOWNERS","security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":"CLA.md"}},"created_at":"2026-03-08T18:55:10.000Z","updated_at":"2026-03-08T19:15:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/itential/asyncgateway","commit_stats":null,"previous_names":["itential/asyncgateway"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/itential/asyncgateway","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itential%2Fasyncgateway","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itential%2Fasyncgateway/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itential%2Fasyncgateway/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itential%2Fasyncgateway/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/itential","download_url":"https://codeload.github.com/itential/asyncgateway/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/itential%2Fasyncgateway/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31356881,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T08:03:20.796Z","status":"ssl_error","status_checked_at":"2026-04-03T08:00:37.834Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-03T14:15:39.050Z","updated_at":"2026-04-03T14:15:39.879Z","avatar_url":"https://github.com/itential.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AsyncGateway\n\n\u003e Async Python client for the Itential Automation Gateway (IAG) 4.x API.\n\n## Overview\n\n`asyncgateway` provides async/await access to IAG 4.x across two layers:\n\n- **Services** (`client.services.*`) — thin async wrappers, one method per API endpoint, returning raw dicts.\n- **Resources** (`client.resources.*`) — declarative abstractions that compose service calls into idempotent operations (`ensure`, `absent`, `run`, `load`, `dump`).\n\nUse services when you need direct API access. Use resources when you want declarative, state-based control.\n\n## Installation\n\n```bash\npip install asyncgateway\n```\n\n```bash\nuv add asyncgateway\n```\n\n**Requires:** Python 3.10+, `ipsdk`\n\n## Usage\n\n### Client initialization\n\n```python\nimport asyncio\nimport asyncgateway\n\nconfig = {\n    \"host\": \"gateway.example.com\",\n    # \"port\": 3000,\n    # \"protocol\": \"https\",\n    # \"username\": \"admin\",\n    # \"password\": \"secret\",\n}\n\nasync def main():\n    async with asyncgateway.client(**config) as client:\n        ...\n\nasyncio.run(main())\n```\n\nAll `**kwargs` are passed through to `ipsdk.gateway_factory()`.\n\n### Services layer\n\nDirect, one-to-one wrappers around IAG API endpoints.\n\n```python\n# Devices\ndevices = await client.services.devices.get_all()\ndevice  = await client.services.devices.get(\"router1\")\nawait client.services.devices.create(\"router1\", {\"ansible_host\": \"192.168.1.1\"})\nawait client.services.devices.patch(\"router1\", {\"ansible_user\": \"admin\"})\nawait client.services.devices.delete(\"router1\")\n\n# Playbooks\nplaybooks = await client.services.playbooks.get_all()\nplaybook  = await client.services.playbooks.get(\"network_config\")\nawait client.services.playbooks.refresh()\nschema = await client.services.playbooks.get_schema(\"network_config\")\nawait client.services.playbooks.update_schema(\"network_config\", schema)\nawait client.services.playbooks.delete_schema(\"network_config\")\n\n# Gateway configuration\nconfig = await client.services.config.get()\nawait client.services.config.update({\"max_concurrent_jobs\": 10})\n```\n\n### Resources layer\n\nDeclarative, idempotent operations that compose service calls.\n\n```python\nfrom asyncgateway.services import Operation\n\n# Ensure a device exists; create if missing, patch variables if present\ndevice = await client.resources.devices.ensure(\"router1\", {\"ansible_host\": \"192.168.1.1\"})\n\n# Ensure a device does not exist (no-op if already absent)\nawait client.resources.devices.absent(\"router1\")\n\n# Bulk load devices from an in-memory list\ndata = [{\"name\": \"router1\", \"variables\": {\"ansible_host\": \"192.168.1.1\"}}]\nresult = await client.resources.devices.load(data, Operation.MERGE)\n\n# Dump all devices to files\nresult = await client.resources.devices.dump(format_type=\"yaml\", individual_files=True)\n\n# Run a playbook\nresult = await client.resources.playbooks.run(\"network_config\", {\"target\": \"router1\"})\n\n# Dry run a playbook\nresult = await client.resources.playbooks.dry_run(\"network_config\", {\"target\": \"router1\"})\n```\n\n**Load operations:**\n\n| Operation | Behavior |\n|-----------|----------|\n| `Operation.MERGE` | Add missing resources; skip existing |\n| `Operation.OVERWRITE` | Add missing; replace existing |\n| `Operation.REPLACE` | Delete all existing, then add from data |\n\n### Bulk file load\n\n`client.load(path, op)` reads JSON/YAML files from `{path}/{service_name}/` and dispatches to each service that supports `load()`:\n\n```python\nresult = await client.load(\"/data\", Operation.MERGE)\n```\n\nYAML support requires `PyYAML` (`uv add PyYAML`). Without it, YAML paths raise `ValidationError`.\n\n## Development\n\n```bash\ngit clone https://github.com/itential/asyncgateway\ncd asyncgateway\nuv sync --group dev\nuv run pytest          # all tests pass without a live IAG instance\nmake ci                # lint + typecheck + security + tests (full local CI)\n```\n\nSee [docs/development.md](docs/development.md) for the full contributor guide and [CONTRIBUTING.md](CONTRIBUTING.md) for contribution guidelines.\n\n## License\n\nGPL-3.0-or-later. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitential%2Fasyncgateway","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fitential%2Fasyncgateway","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fitential%2Fasyncgateway/lists"}