asa-api-client 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. asa_api_client-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +80 -0
  2. asa_api_client-0.1.0/.github/ISSUE_TEMPLATE/config.yml +5 -0
  3. asa_api_client-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +37 -0
  4. asa_api_client-0.1.0/.github/dependabot.yml +24 -0
  5. asa_api_client-0.1.0/.github/workflows/ci.yml +46 -0
  6. asa_api_client-0.1.0/.github/workflows/docs.yml +54 -0
  7. asa_api_client-0.1.0/.github/workflows/publish.yml +29 -0
  8. asa_api_client-0.1.0/.gitignore +57 -0
  9. asa_api_client-0.1.0/LICENSE +21 -0
  10. asa_api_client-0.1.0/PKG-INFO +236 -0
  11. asa_api_client-0.1.0/README.md +193 -0
  12. asa_api_client-0.1.0/asa_api_client/__init__.py +50 -0
  13. asa_api_client-0.1.0/asa_api_client/auth.py +462 -0
  14. asa_api_client-0.1.0/asa_api_client/client.py +332 -0
  15. asa_api_client-0.1.0/asa_api_client/exceptions.py +221 -0
  16. asa_api_client-0.1.0/asa_api_client/logging.py +128 -0
  17. asa_api_client-0.1.0/asa_api_client/models/__init__.py +106 -0
  18. asa_api_client-0.1.0/asa_api_client/models/ad_groups.py +301 -0
  19. asa_api_client-0.1.0/asa_api_client/models/base.py +345 -0
  20. asa_api_client-0.1.0/asa_api_client/models/campaigns.py +255 -0
  21. asa_api_client-0.1.0/asa_api_client/models/keywords.py +196 -0
  22. asa_api_client-0.1.0/asa_api_client/models/reports.py +359 -0
  23. asa_api_client-0.1.0/asa_api_client/resources/__init__.py +19 -0
  24. asa_api_client-0.1.0/asa_api_client/resources/ad_groups.py +152 -0
  25. asa_api_client-0.1.0/asa_api_client/resources/base.py +593 -0
  26. asa_api_client-0.1.0/asa_api_client/resources/campaigns.py +158 -0
  27. asa_api_client-0.1.0/asa_api_client/resources/keywords.py +269 -0
  28. asa_api_client-0.1.0/asa_api_client/resources/reports.py +504 -0
  29. asa_api_client-0.1.0/asa_api_client/settings.py +126 -0
  30. asa_api_client-0.1.0/asa_api_client/utils/__init__.py +1 -0
  31. asa_api_client-0.1.0/docs/CNAME +1 -0
  32. asa_api_client-0.1.0/docs/api/client.md +10 -0
  33. asa_api_client-0.1.0/docs/api/exceptions.md +90 -0
  34. asa_api_client-0.1.0/docs/api/models.md +54 -0
  35. asa_api_client-0.1.0/docs/getting-started/authentication.md +75 -0
  36. asa_api_client-0.1.0/docs/getting-started/installation.md +45 -0
  37. asa_api_client-0.1.0/docs/getting-started/quickstart.md +86 -0
  38. asa_api_client-0.1.0/docs/guide/ad-groups.md +57 -0
  39. asa_api_client-0.1.0/docs/guide/async.md +80 -0
  40. asa_api_client-0.1.0/docs/guide/campaigns.md +79 -0
  41. asa_api_client-0.1.0/docs/guide/keywords.md +70 -0
  42. asa_api_client-0.1.0/docs/guide/reports.md +87 -0
  43. asa_api_client-0.1.0/docs/index.md +45 -0
  44. asa_api_client-0.1.0/mkdocs.yml +71 -0
  45. asa_api_client-0.1.0/pyproject.toml +133 -0
  46. asa_api_client-0.1.0/tests/__init__.py +1 -0
  47. asa_api_client-0.1.0/tests/unit/__init__.py +1 -0
  48. asa_api_client-0.1.0/tests/unit/test_models.py +93 -0
  49. asa_api_client-0.1.0/uv.lock +1295 -0
@@ -0,0 +1,80 @@
1
+ name: Bug Report
2
+ description: Report a bug or unexpected behavior
3
+ labels: ["type: bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Thanks for taking the time to report a bug! Please fill out the form below.
9
+
10
+ - type: textarea
11
+ id: description
12
+ attributes:
13
+ label: Description
14
+ description: A clear and concise description of what the bug is.
15
+ placeholder: Describe the bug...
16
+ validations:
17
+ required: true
18
+
19
+ - type: textarea
20
+ id: reproduction
21
+ attributes:
22
+ label: Steps to Reproduce
23
+ description: Steps to reproduce the behavior.
24
+ placeholder: |
25
+ 1. Create a client with...
26
+ 2. Call method...
27
+ 3. See error...
28
+ validations:
29
+ required: true
30
+
31
+ - type: textarea
32
+ id: expected
33
+ attributes:
34
+ label: Expected Behavior
35
+ description: What you expected to happen.
36
+ validations:
37
+ required: true
38
+
39
+ - type: textarea
40
+ id: actual
41
+ attributes:
42
+ label: Actual Behavior
43
+ description: What actually happened.
44
+ validations:
45
+ required: true
46
+
47
+ - type: input
48
+ id: version
49
+ attributes:
50
+ label: Package Version
51
+ description: What version of search-ads-api are you using?
52
+ placeholder: "0.1.0"
53
+ validations:
54
+ required: true
55
+
56
+ - type: input
57
+ id: python-version
58
+ attributes:
59
+ label: Python Version
60
+ description: What version of Python are you using?
61
+ placeholder: "3.13.0"
62
+ validations:
63
+ required: true
64
+
65
+ - type: dropdown
66
+ id: os
67
+ attributes:
68
+ label: Operating System
69
+ options:
70
+ - macOS
71
+ - Linux
72
+ - Windows
73
+ validations:
74
+ required: true
75
+
76
+ - type: textarea
77
+ id: additional
78
+ attributes:
79
+ label: Additional Context
80
+ description: Any other context about the problem (logs, screenshots, etc.)
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Question or Discussion
4
+ url: https://github.com/SamPetherbridge/asa-api-client/discussions
5
+ about: Ask questions or start a discussion
@@ -0,0 +1,37 @@
1
+ name: Feature Request
2
+ description: Suggest a new feature or enhancement
3
+ labels: ["type: feature"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Thanks for suggesting a feature! Please fill out the form below.
9
+
10
+ - type: textarea
11
+ id: problem
12
+ attributes:
13
+ label: Problem Statement
14
+ description: What problem would this feature solve? Is it related to a frustration?
15
+ placeholder: I'm always frustrated when...
16
+ validations:
17
+ required: true
18
+
19
+ - type: textarea
20
+ id: solution
21
+ attributes:
22
+ label: Proposed Solution
23
+ description: Describe the solution you'd like to see.
24
+ validations:
25
+ required: true
26
+
27
+ - type: textarea
28
+ id: alternatives
29
+ attributes:
30
+ label: Alternatives Considered
31
+ description: Have you considered any alternative solutions or workarounds?
32
+
33
+ - type: textarea
34
+ id: additional
35
+ attributes:
36
+ label: Additional Context
37
+ description: Any other context, screenshots, or examples.
@@ -0,0 +1,24 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ commit-message:
8
+ prefix: "⬆️"
9
+ labels:
10
+ - "dependencies"
11
+ groups:
12
+ python-packages:
13
+ patterns:
14
+ - "*"
15
+
16
+ - package-ecosystem: "github-actions"
17
+ directory: "/"
18
+ schedule:
19
+ interval: "weekly"
20
+ commit-message:
21
+ prefix: "👷"
22
+ labels:
23
+ - "dependencies"
24
+ - "github-actions"
@@ -0,0 +1,46 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v6
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v7
21
+ with:
22
+ version: "latest"
23
+
24
+ - name: Set up Python ${{ matrix.python-version }}
25
+ run: uv python install ${{ matrix.python-version }}
26
+
27
+ - name: Install dependencies
28
+ run: uv sync --extra dev
29
+
30
+ - name: Run linting
31
+ run: uv run ruff check .
32
+
33
+ - name: Run formatting check
34
+ run: uv run ruff format --check .
35
+
36
+ - name: Run type checking
37
+ run: uv run mypy asa_api_client
38
+
39
+ - name: Run tests
40
+ run: uv run pytest --cov=asa_api_client --cov-report=xml
41
+
42
+ - name: Upload coverage to Codecov
43
+ uses: codecov/codecov-action@v5
44
+ with:
45
+ file: ./coverage.xml
46
+ fail_ci_if_error: false
@@ -0,0 +1,54 @@
1
+ name: Deploy Documentation
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: "pages"
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v4
25
+ with:
26
+ version: "latest"
27
+
28
+ - name: Set up Python
29
+ run: uv python install 3.13
30
+
31
+ - name: Install dependencies
32
+ run: uv sync --extra docs
33
+
34
+ - name: Build documentation
35
+ run: uv run mkdocs build
36
+
37
+ - name: Setup Pages
38
+ uses: actions/configure-pages@v4
39
+
40
+ - name: Upload artifact
41
+ uses: actions/upload-pages-artifact@v3
42
+ with:
43
+ path: site
44
+
45
+ deploy:
46
+ environment:
47
+ name: github-pages
48
+ url: ${{ steps.deployment.outputs.page_url }}
49
+ runs-on: ubuntu-latest
50
+ needs: build
51
+ steps:
52
+ - name: Deploy to GitHub Pages
53
+ id: deployment
54
+ uses: actions/deploy-pages@v4
@@ -0,0 +1,29 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ jobs:
8
+ publish:
9
+ runs-on: ubuntu-latest
10
+ environment: pypi
11
+ permissions:
12
+ id-token: write # Required for trusted publishing
13
+
14
+ steps:
15
+ - uses: actions/checkout@v6
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v7
19
+ with:
20
+ version: "latest"
21
+
22
+ - name: Set up Python
23
+ run: uv python install 3.13
24
+
25
+ - name: Build package
26
+ run: uv build
27
+
28
+ - name: Publish to PyPI
29
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,57 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ .Python
7
+ build/
8
+ develop-eggs/
9
+ dist/
10
+ downloads/
11
+ eggs/
12
+ .eggs/
13
+ lib/
14
+ lib64/
15
+ parts/
16
+ sdist/
17
+ var/
18
+ wheels/
19
+ *.egg-info/
20
+ .installed.cfg
21
+ *.egg
22
+
23
+ # Virtual environments
24
+ .venv/
25
+ venv/
26
+ ENV/
27
+
28
+ # IDE
29
+ .idea/
30
+ .vscode/
31
+ *.swp
32
+ *.swo
33
+
34
+ # Testing
35
+ .pytest_cache/
36
+ .coverage
37
+ htmlcov/
38
+ .tox/
39
+ .nox/
40
+
41
+ # mypy
42
+ .mypy_cache/
43
+
44
+ # ruff
45
+ .ruff_cache/
46
+
47
+ # Documentation
48
+ site/
49
+
50
+ # Environment
51
+ .env
52
+ .env.local
53
+ *.pem
54
+
55
+ # OS
56
+ .DS_Store
57
+ Thumbs.db
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Peth Pty Ltd
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,236 @@
1
+ Metadata-Version: 2.4
2
+ Name: asa-api-client
3
+ Version: 0.1.0
4
+ Summary: A modern Python client for the Apple Search Ads API with full type safety and async support
5
+ Project-URL: Homepage, https://github.com/SamPetherbridge/asa-api-client
6
+ Project-URL: Documentation, https://asa-api-client.peth.au
7
+ Project-URL: Repository, https://github.com/SamPetherbridge/asa-api-client
8
+ Project-URL: Issues, https://github.com/SamPetherbridge/asa-api-client/issues
9
+ Author-email: Peth Pty Ltd <hello@peth.com.au>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: advertising,api,apple,asa,async,pydantic,search-ads
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Framework :: Pydantic :: 2
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.13
22
+ Requires-Dist: httpx>=0.27.0
23
+ Requires-Dist: pydantic-settings>=2.6.0
24
+ Requires-Dist: pydantic>=2.10.0
25
+ Requires-Dist: pyjwt[crypto]>=2.9.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: mypy>=1.13.0; extra == 'dev'
28
+ Requires-Dist: pandas-stubs>=2.2.0; extra == 'dev'
29
+ Requires-Dist: pandas>=2.2.0; extra == 'dev'
30
+ Requires-Dist: pre-commit>=4.0.0; extra == 'dev'
31
+ Requires-Dist: pytest-asyncio>=0.24.0; extra == 'dev'
32
+ Requires-Dist: pytest-cov>=6.0.0; extra == 'dev'
33
+ Requires-Dist: pytest-httpx>=0.34.0; extra == 'dev'
34
+ Requires-Dist: pytest>=8.3.0; extra == 'dev'
35
+ Requires-Dist: ruff>=0.8.0; extra == 'dev'
36
+ Provides-Extra: docs
37
+ Requires-Dist: mkdocs-material>=9.5.0; extra == 'docs'
38
+ Requires-Dist: mkdocs>=1.6.0; extra == 'docs'
39
+ Requires-Dist: mkdocstrings[python]>=0.27.0; extra == 'docs'
40
+ Provides-Extra: pandas
41
+ Requires-Dist: pandas>=2.2.0; extra == 'pandas'
42
+ Description-Content-Type: text/markdown
43
+
44
+ # ASA API Client
45
+
46
+ [![PyPI version](https://img.shields.io/pypi/v/asa-api-client.svg)](https://pypi.org/project/asa-api-client/)
47
+ [![Python](https://img.shields.io/pypi/pyversions/asa-api-client.svg)](https://pypi.org/project/asa-api-client/)
48
+ [![License](https://img.shields.io/github/license/SamPetherbridge/asa-api-client.svg)](https://github.com/SamPetherbridge/asa-api-client/blob/main/LICENSE)
49
+ [![CI](https://github.com/SamPetherbridge/asa-api-client/actions/workflows/ci.yml/badge.svg)](https://github.com/SamPetherbridge/asa-api-client/actions/workflows/ci.yml)
50
+
51
+ A modern, fully-typed Python client for the Apple Search Ads API with async support and Pydantic models.
52
+
53
+ ## Features
54
+
55
+ - **Full Type Safety** - Complete type hints with strict mypy compliance
56
+ - **Async Support** - Both sync and async methods in a unified client
57
+ - **Pydantic Models** - Validated request/response models
58
+ - **Resource-based API** - Intuitive `client.campaigns.list()` pattern
59
+ - **Automatic Pagination** - `iter_all()` and `iter_all_async()` helpers
60
+ - **Reports with Pandas** - Optional DataFrame export
61
+
62
+ ## Installation
63
+
64
+ Using [uv](https://docs.astral.sh/uv/) (recommended):
65
+
66
+ ```bash
67
+ uv add asa-api-client
68
+ ```
69
+
70
+ Using pip:
71
+
72
+ ```bash
73
+ pip install asa-api-client
74
+ ```
75
+
76
+ With pandas support:
77
+
78
+ ```bash
79
+ uv add "asa-api-client[pandas]"
80
+ # or
81
+ pip install "asa-api-client[pandas]"
82
+ ```
83
+
84
+ ## Quick Start
85
+
86
+ ```python
87
+ from asa_api_client import AppleSearchAdsClient
88
+
89
+ # From environment variables
90
+ client = AppleSearchAdsClient.from_env()
91
+
92
+ # Or explicit configuration
93
+ client = AppleSearchAdsClient(
94
+ client_id="SEARCHADS.xxx",
95
+ team_id="SEARCHADS.xxx",
96
+ key_id="xxx",
97
+ org_id=123456,
98
+ private_key_path="private-key.pem",
99
+ )
100
+
101
+ # List campaigns
102
+ with client:
103
+ campaigns = client.campaigns.list()
104
+ for campaign in campaigns:
105
+ print(f"{campaign.name}: {campaign.status}")
106
+ ```
107
+
108
+ ## Environment Variables
109
+
110
+ ```bash
111
+ export ASA_CLIENT_ID="SEARCHADS.your-client-id"
112
+ export ASA_TEAM_ID="SEARCHADS.your-team-id"
113
+ export ASA_KEY_ID="your-key-id"
114
+ export ASA_ORG_ID="123456"
115
+ export ASA_PRIVATE_KEY_PATH="/path/to/private-key.pem"
116
+ ```
117
+
118
+ Or use a `.env` file:
119
+
120
+ ```bash
121
+ ASA_CLIENT_ID=SEARCHADS.your-client-id
122
+ ASA_TEAM_ID=SEARCHADS.your-team-id
123
+ ASA_KEY_ID=your-key-id
124
+ ASA_ORG_ID=123456
125
+ ASA_PRIVATE_KEY_PATH=private-key.pem
126
+ ```
127
+
128
+ ## Resources
129
+
130
+ ### Campaigns
131
+
132
+ ```python
133
+ # List all campaigns
134
+ campaigns = client.campaigns.list()
135
+
136
+ # Get a specific campaign
137
+ campaign = client.campaigns.get(campaign_id)
138
+
139
+ # Find with filters
140
+ from asa_api_client.models import Selector
141
+ enabled = client.campaigns.find(
142
+ Selector().where("status", "==", "ENABLED")
143
+ )
144
+
145
+ # Create a campaign
146
+ from asa_api_client.models import CampaignCreate, Money, CampaignSupplySource
147
+ campaign = client.campaigns.create(
148
+ CampaignCreate(
149
+ name="My Campaign",
150
+ adam_id=123456789,
151
+ countries_or_regions=["US"],
152
+ daily_budget_amount=Money(amount="100", currency="USD"),
153
+ supply_sources=[CampaignSupplySource.APPSTORE_SEARCH_RESULTS],
154
+ )
155
+ )
156
+ ```
157
+
158
+ ### Ad Groups
159
+
160
+ ```python
161
+ # Access ad groups through campaign
162
+ ad_groups = client.campaigns(campaign_id).ad_groups.list()
163
+
164
+ # Create an ad group
165
+ from asa_api_client.models import AdGroupCreate
166
+ ad_group = client.campaigns(campaign_id).ad_groups.create(
167
+ AdGroupCreate(
168
+ name="My Ad Group",
169
+ default_bid_amount=Money(amount="1.00", currency="USD"),
170
+ )
171
+ )
172
+ ```
173
+
174
+ ### Keywords
175
+
176
+ ```python
177
+ # List keywords in an ad group
178
+ keywords = client.campaigns(campaign_id).ad_groups(ad_group_id).keywords.list()
179
+
180
+ # Create keywords (bulk only)
181
+ from asa_api_client.models import KeywordCreate, KeywordMatchType
182
+ result = client.campaigns(campaign_id).ad_groups(ad_group_id).keywords.create_bulk([
183
+ KeywordCreate(
184
+ text="my keyword",
185
+ match_type=KeywordMatchType.EXACT,
186
+ bid_amount=Money(amount="1.50", currency="USD"),
187
+ )
188
+ ])
189
+ ```
190
+
191
+ ### Reports
192
+
193
+ ```python
194
+ from datetime import date
195
+
196
+ # Campaign report
197
+ report = client.reports.campaigns(
198
+ start_date=date(2024, 1, 1),
199
+ end_date=date(2024, 1, 31),
200
+ )
201
+
202
+ # Convert to DataFrame (requires pandas)
203
+ df = report.to_dataframe()
204
+ ```
205
+
206
+ ## Async Usage
207
+
208
+ ```python
209
+ import asyncio
210
+
211
+ async def main():
212
+ client = AppleSearchAdsClient.from_env()
213
+
214
+ async with client:
215
+ campaigns = await client.campaigns.list_async()
216
+
217
+ # Async iteration
218
+ async for campaign in client.campaigns.iter_all_async():
219
+ print(campaign.name)
220
+
221
+ asyncio.run(main())
222
+ ```
223
+
224
+ ## CLI
225
+
226
+ For a command-line interface, install [search-ads-cli](https://github.com/SamPetherbridge/search-ads-cli):
227
+
228
+ ```bash
229
+ uv add search-ads-cli
230
+ # or
231
+ pip install search-ads-cli
232
+ ```
233
+
234
+ ## License
235
+
236
+ MIT License - Copyright (c) 2025 Peth Pty Ltd