affinity-sdk 0.2.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.
- affinity_sdk-0.2.0/.editorconfig +19 -0
- affinity_sdk-0.2.0/.env.example +3 -0
- affinity_sdk-0.2.0/.gitattributes +7 -0
- affinity_sdk-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +44 -0
- affinity_sdk-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +27 -0
- affinity_sdk-0.2.0/.github/dependabot.yml +12 -0
- affinity_sdk-0.2.0/.github/pull_request_template.md +14 -0
- affinity_sdk-0.2.0/.github/workflows/ci.yml +56 -0
- affinity_sdk-0.2.0/.github/workflows/docs.yml +97 -0
- affinity_sdk-0.2.0/.github/workflows/linkcheck.yml +44 -0
- affinity_sdk-0.2.0/.github/workflows/openapi-validation.yml +30 -0
- affinity_sdk-0.2.0/.github/workflows/release.yml +178 -0
- affinity_sdk-0.2.0/.gitignore +55 -0
- affinity_sdk-0.2.0/.pre-commit-config.yaml +30 -0
- affinity_sdk-0.2.0/CHANGELOG.md +18 -0
- affinity_sdk-0.2.0/CODE_OF_CONDUCT.md +96 -0
- affinity_sdk-0.2.0/CONTRIBUTING.md +60 -0
- affinity_sdk-0.2.0/LICENSE +21 -0
- affinity_sdk-0.2.0/PKG-INFO +538 -0
- affinity_sdk-0.2.0/README.md +494 -0
- affinity_sdk-0.2.0/SECURITY.md +10 -0
- affinity_sdk-0.2.0/affinity/__init__.py +100 -0
- affinity_sdk-0.2.0/affinity/client.py +517 -0
- affinity_sdk-0.2.0/affinity/clients/__init__.py +19 -0
- affinity_sdk-0.2.0/affinity/clients/http.py +1717 -0
- affinity_sdk-0.2.0/affinity/exceptions.py +445 -0
- affinity_sdk-0.2.0/affinity/filters.py +290 -0
- affinity_sdk-0.2.0/affinity/hooks.py +17 -0
- affinity_sdk-0.2.0/affinity/models/__init__.py +152 -0
- affinity_sdk-0.2.0/affinity/models/entities.py +579 -0
- affinity_sdk-0.2.0/affinity/models/pagination.py +245 -0
- affinity_sdk-0.2.0/affinity/models/secondary.py +387 -0
- affinity_sdk-0.2.0/affinity/models/types.py +425 -0
- affinity_sdk-0.2.0/affinity/progress.py +22 -0
- affinity_sdk-0.2.0/affinity/py.typed +0 -0
- affinity_sdk-0.2.0/affinity/services/__init__.py +38 -0
- affinity_sdk-0.2.0/affinity/services/companies.py +532 -0
- affinity_sdk-0.2.0/affinity/services/lists.py +761 -0
- affinity_sdk-0.2.0/affinity/services/opportunities.py +306 -0
- affinity_sdk-0.2.0/affinity/services/persons.py +517 -0
- affinity_sdk-0.2.0/affinity/services/tasks.py +193 -0
- affinity_sdk-0.2.0/affinity/services/v1_only.py +1010 -0
- affinity_sdk-0.2.0/affinity/types.py +73 -0
- affinity_sdk-0.2.0/docs/public/changelog.md +3 -0
- affinity_sdk-0.2.0/docs/public/examples.md +33 -0
- affinity_sdk-0.2.0/docs/public/getting-started.md +90 -0
- affinity_sdk-0.2.0/docs/public/glossary.md +22 -0
- affinity_sdk-0.2.0/docs/public/guides/api-versions-and-routing.md +46 -0
- affinity_sdk-0.2.0/docs/public/guides/authentication.md +29 -0
- affinity_sdk-0.2.0/docs/public/guides/configuration.md +122 -0
- affinity_sdk-0.2.0/docs/public/guides/debugging-hooks.md +22 -0
- affinity_sdk-0.2.0/docs/public/guides/errors-and-retries.md +81 -0
- affinity_sdk-0.2.0/docs/public/guides/field-types-and-values.md +67 -0
- affinity_sdk-0.2.0/docs/public/guides/filtering.md +39 -0
- affinity_sdk-0.2.0/docs/public/guides/ids-and-types.md +21 -0
- affinity_sdk-0.2.0/docs/public/guides/models.md +41 -0
- affinity_sdk-0.2.0/docs/public/guides/pagination.md +23 -0
- affinity_sdk-0.2.0/docs/public/guides/rate-limits.md +34 -0
- affinity_sdk-0.2.0/docs/public/guides/sync-vs-async.md +55 -0
- affinity_sdk-0.2.0/docs/public/guides/v1-v2-routing.md +3 -0
- affinity_sdk-0.2.0/docs/public/guides/webhooks.md +59 -0
- affinity_sdk-0.2.0/docs/public/index.md +31 -0
- affinity_sdk-0.2.0/docs/public/reference/client.md +9 -0
- affinity_sdk-0.2.0/docs/public/reference/exceptions.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/filters.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/models.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/companies.md +5 -0
- affinity_sdk-0.2.0/docs/public/reference/services/lists.md +5 -0
- affinity_sdk-0.2.0/docs/public/reference/services/opportunities.md +5 -0
- affinity_sdk-0.2.0/docs/public/reference/services/persons.md +5 -0
- affinity_sdk-0.2.0/docs/public/reference/services/tasks.md +5 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/auth.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/field-values.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/fields.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/files.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/interactions.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/notes.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/relationships.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/reminders.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/services/v1/webhooks.md +3 -0
- affinity_sdk-0.2.0/docs/public/reference/types.md +3 -0
- affinity_sdk-0.2.0/docs/public/troubleshooting.md +22 -0
- affinity_sdk-0.2.0/examples/advanced_usage.py +476 -0
- affinity_sdk-0.2.0/examples/async_lifecycle.py +43 -0
- affinity_sdk-0.2.0/examples/basic_usage.py +72 -0
- affinity_sdk-0.2.0/examples/filter_builder.py +36 -0
- affinity_sdk-0.2.0/examples/hooks_debugging.py +40 -0
- affinity_sdk-0.2.0/examples/list_management.py +120 -0
- affinity_sdk-0.2.0/examples/resolve_helpers.py +38 -0
- affinity_sdk-0.2.0/examples/task_polling.py +34 -0
- affinity_sdk-0.2.0/mkdocs.yml +75 -0
- affinity_sdk-0.2.0/pyproject.toml +159 -0
- affinity_sdk-0.2.0/tests/conftest.py +180 -0
- affinity_sdk-0.2.0/tests/test_affinity_client_wrapper_additional_coverage.py +57 -0
- affinity_sdk-0.2.0/tests/test_client.py +1163 -0
- affinity_sdk-0.2.0/tests/test_env_helpers.py +51 -0
- affinity_sdk-0.2.0/tests/test_file_download_streaming.py +154 -0
- affinity_sdk-0.2.0/tests/test_file_upload_helpers_and_validation.py +91 -0
- affinity_sdk-0.2.0/tests/test_http_client_additional_coverage.py +401 -0
- affinity_sdk-0.2.0/tests/test_http_client_remaining_coverage.py +1505 -0
- affinity_sdk-0.2.0/tests/test_integration_smoke.py +36 -0
- affinity_sdk-0.2.0/tests/test_interactions_and_files_regressions.py +196 -0
- affinity_sdk-0.2.0/tests/test_list_entry_membership_and_opportunities.py +209 -0
- affinity_sdk-0.2.0/tests/test_models.py +660 -0
- affinity_sdk-0.2.0/tests/test_new_features.py +712 -0
- affinity_sdk-0.2.0/tests/test_pagination_iterators.py +122 -0
- affinity_sdk-0.2.0/tests/test_requirements_additional.py +211 -0
- affinity_sdk-0.2.0/tests/test_services_lists_additional_coverage.py +682 -0
- affinity_sdk-0.2.0/tests/test_services_opportunities_tasks_additional_coverage.py +386 -0
- affinity_sdk-0.2.0/tests/test_services_persons_companies_additional_coverage.py +944 -0
- affinity_sdk-0.2.0/tests/test_small_modules_coverage.py +173 -0
- affinity_sdk-0.2.0/tests/test_v1_only_services_additional_coverage.py +491 -0
- affinity_sdk-0.2.0/tests/test_v1_only_services_more_coverage.py +585 -0
- affinity_sdk-0.2.0/tools/generate_requirements_mapping.py +140 -0
- affinity_sdk-0.2.0/tools/validate_openapi_models.py +436 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
root = true
|
|
2
|
+
|
|
3
|
+
[*]
|
|
4
|
+
charset = utf-8
|
|
5
|
+
end_of_line = lf
|
|
6
|
+
insert_final_newline = true
|
|
7
|
+
trim_trailing_whitespace = true
|
|
8
|
+
|
|
9
|
+
[*.py]
|
|
10
|
+
indent_style = space
|
|
11
|
+
indent_size = 4
|
|
12
|
+
max_line_length = 100
|
|
13
|
+
|
|
14
|
+
[*.{yml,yaml}]
|
|
15
|
+
indent_style = space
|
|
16
|
+
indent_size = 2
|
|
17
|
+
|
|
18
|
+
[*.md]
|
|
19
|
+
trim_trailing_whitespace = false
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Bug report
|
|
2
|
+
description: Report a problem with the SDK
|
|
3
|
+
labels: [bug]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to report an issue.
|
|
9
|
+
|
|
10
|
+
- type: textarea
|
|
11
|
+
id: what-happened
|
|
12
|
+
attributes:
|
|
13
|
+
label: What happened?
|
|
14
|
+
description: What did you expect to happen, and what happened instead?
|
|
15
|
+
validations:
|
|
16
|
+
required: true
|
|
17
|
+
|
|
18
|
+
- type: textarea
|
|
19
|
+
id: reproduction
|
|
20
|
+
attributes:
|
|
21
|
+
label: Reproduction steps
|
|
22
|
+
description: Minimal steps/code to reproduce the issue.
|
|
23
|
+
render: python
|
|
24
|
+
validations:
|
|
25
|
+
required: true
|
|
26
|
+
|
|
27
|
+
- type: input
|
|
28
|
+
id: version
|
|
29
|
+
attributes:
|
|
30
|
+
label: affinity-sdk version
|
|
31
|
+
placeholder: e.g. 0.1.0
|
|
32
|
+
validations:
|
|
33
|
+
required: false
|
|
34
|
+
|
|
35
|
+
- type: textarea
|
|
36
|
+
id: environment
|
|
37
|
+
attributes:
|
|
38
|
+
label: Environment
|
|
39
|
+
description: OS, Python version, etc.
|
|
40
|
+
placeholder: |
|
|
41
|
+
- OS:
|
|
42
|
+
- Python:
|
|
43
|
+
validations:
|
|
44
|
+
required: false
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Suggest an idea or enhancement
|
|
3
|
+
labels: [enhancement]
|
|
4
|
+
body:
|
|
5
|
+
- type: textarea
|
|
6
|
+
id: problem
|
|
7
|
+
attributes:
|
|
8
|
+
label: Problem / use case
|
|
9
|
+
description: What are you trying to accomplish?
|
|
10
|
+
validations:
|
|
11
|
+
required: true
|
|
12
|
+
|
|
13
|
+
- type: textarea
|
|
14
|
+
id: proposal
|
|
15
|
+
attributes:
|
|
16
|
+
label: Proposed solution
|
|
17
|
+
description: What would you like to see added/changed?
|
|
18
|
+
validations:
|
|
19
|
+
required: true
|
|
20
|
+
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: alternatives
|
|
23
|
+
attributes:
|
|
24
|
+
label: Alternatives considered
|
|
25
|
+
description: Any other approaches you've tried or considered.
|
|
26
|
+
validations:
|
|
27
|
+
required: false
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
test:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
strategy:
|
|
11
|
+
fail-fast: false
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: ${{ matrix.python-version }}
|
|
22
|
+
cache: pip
|
|
23
|
+
cache-dependency-path: pyproject.toml
|
|
24
|
+
|
|
25
|
+
- name: Install
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
python -m pip install -e ".[dev]"
|
|
29
|
+
|
|
30
|
+
- name: Lint
|
|
31
|
+
run: |
|
|
32
|
+
ruff format --check .
|
|
33
|
+
ruff check .
|
|
34
|
+
|
|
35
|
+
- name: Type check
|
|
36
|
+
run: |
|
|
37
|
+
mypy affinity
|
|
38
|
+
|
|
39
|
+
- name: Test
|
|
40
|
+
run: |
|
|
41
|
+
pytest --cov=affinity --cov-report=term-missing --cov-report=xml
|
|
42
|
+
|
|
43
|
+
- name: Upload coverage to Codecov
|
|
44
|
+
uses: codecov/codecov-action@v5
|
|
45
|
+
with:
|
|
46
|
+
files: ./coverage.xml
|
|
47
|
+
fail_ci_if_error: false
|
|
48
|
+
|
|
49
|
+
- name: Traceability mapping is up to date
|
|
50
|
+
run: |
|
|
51
|
+
if [ -d docs/internal ]; then
|
|
52
|
+
python tools/generate_requirements_mapping.py
|
|
53
|
+
git diff --exit-code docs/internal/requirements_to_tests_mapping.md
|
|
54
|
+
else
|
|
55
|
+
echo "Skipping traceability mapping (docs/internal not present in repo checkout)."
|
|
56
|
+
fi
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches: ["main"]
|
|
7
|
+
tags: ["v*.*.*"]
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
with:
|
|
18
|
+
fetch-depth: 0
|
|
19
|
+
|
|
20
|
+
- name: Set up Python
|
|
21
|
+
uses: actions/setup-python@v5
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.12"
|
|
24
|
+
cache: pip
|
|
25
|
+
cache-dependency-path: pyproject.toml
|
|
26
|
+
|
|
27
|
+
- name: Install
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
python -m pip install -e ".[docs]"
|
|
31
|
+
|
|
32
|
+
- name: Smoke import
|
|
33
|
+
run: |
|
|
34
|
+
python -c "import affinity; print(affinity.__version__)"
|
|
35
|
+
|
|
36
|
+
- name: Build
|
|
37
|
+
run: |
|
|
38
|
+
mkdocs build -s
|
|
39
|
+
|
|
40
|
+
- name: Check internal links
|
|
41
|
+
uses: lycheeverse/lychee-action@v2
|
|
42
|
+
with:
|
|
43
|
+
args: >-
|
|
44
|
+
--no-progress
|
|
45
|
+
--exclude '^https?://'
|
|
46
|
+
--exclude '^mailto:'
|
|
47
|
+
site/
|
|
48
|
+
|
|
49
|
+
deploy:
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
needs: build
|
|
52
|
+
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
|
53
|
+
permissions:
|
|
54
|
+
contents: write
|
|
55
|
+
concurrency:
|
|
56
|
+
group: docs-deploy
|
|
57
|
+
cancel-in-progress: true
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
with:
|
|
61
|
+
fetch-depth: 0
|
|
62
|
+
|
|
63
|
+
- name: Set up Python
|
|
64
|
+
uses: actions/setup-python@v5
|
|
65
|
+
with:
|
|
66
|
+
python-version: "3.12"
|
|
67
|
+
cache: pip
|
|
68
|
+
cache-dependency-path: pyproject.toml
|
|
69
|
+
|
|
70
|
+
- name: Install
|
|
71
|
+
run: |
|
|
72
|
+
python -m pip install --upgrade pip
|
|
73
|
+
python -m pip install -e ".[docs]"
|
|
74
|
+
|
|
75
|
+
- name: Smoke import
|
|
76
|
+
run: |
|
|
77
|
+
python -c "import affinity; print(affinity.__version__)"
|
|
78
|
+
|
|
79
|
+
- name: Configure git
|
|
80
|
+
run: |
|
|
81
|
+
git config user.name "github-actions[bot]"
|
|
82
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
83
|
+
|
|
84
|
+
- name: Deploy (dev)
|
|
85
|
+
if: github.ref == 'refs/heads/main'
|
|
86
|
+
run: |
|
|
87
|
+
mike deploy --push dev
|
|
88
|
+
if ! mike list | awk '{print $1}' | grep -Fxq latest; then
|
|
89
|
+
mike set-default --push dev
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
- name: Deploy (release)
|
|
93
|
+
if: startsWith(github.ref, 'refs/tags/v')
|
|
94
|
+
run: |
|
|
95
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
96
|
+
mike deploy --push --update-aliases "${VERSION}" latest
|
|
97
|
+
mike set-default --push latest
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Link Check (External)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: "0 7 * * 1" # Mondays at 07:00 UTC
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
linkcheck:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 10
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
- name: Set up Python
|
|
19
|
+
uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
cache: pip
|
|
23
|
+
cache-dependency-path: pyproject.toml
|
|
24
|
+
|
|
25
|
+
- name: Install
|
|
26
|
+
run: |
|
|
27
|
+
python -m pip install --upgrade pip
|
|
28
|
+
python -m pip install -e ".[docs]"
|
|
29
|
+
|
|
30
|
+
- name: Build
|
|
31
|
+
run: |
|
|
32
|
+
mkdocs build -s
|
|
33
|
+
|
|
34
|
+
- name: Check links (including external)
|
|
35
|
+
uses: lycheeverse/lychee-action@v2
|
|
36
|
+
with:
|
|
37
|
+
args: >-
|
|
38
|
+
--no-progress
|
|
39
|
+
--max-concurrency 8
|
|
40
|
+
--max-retries 2
|
|
41
|
+
--retry-wait-time 2
|
|
42
|
+
--timeout 20
|
|
43
|
+
--exclude '^mailto:'
|
|
44
|
+
site/
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
name: OpenAPI Validation
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
schedule:
|
|
6
|
+
- cron: "0 7 * * 1" # Mondays at 07:00 UTC
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
validate:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
timeout-minutes: 10
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Python
|
|
17
|
+
uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.12"
|
|
20
|
+
cache: pip
|
|
21
|
+
cache-dependency-path: pyproject.toml
|
|
22
|
+
|
|
23
|
+
- name: Install
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip
|
|
26
|
+
python -m pip install -e ".[dev]"
|
|
27
|
+
|
|
28
|
+
- name: Validate OpenAPI alignment
|
|
29
|
+
run: |
|
|
30
|
+
python tools/validate_openapi_models.py
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
name: Release (PyPI)
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*.*.*"]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
target:
|
|
9
|
+
description: "Publish target (manual runs only)"
|
|
10
|
+
required: true
|
|
11
|
+
default: "none"
|
|
12
|
+
type: choice
|
|
13
|
+
options:
|
|
14
|
+
- none
|
|
15
|
+
- testpypi
|
|
16
|
+
|
|
17
|
+
permissions:
|
|
18
|
+
contents: read
|
|
19
|
+
id-token: write
|
|
20
|
+
attestations: write
|
|
21
|
+
|
|
22
|
+
concurrency:
|
|
23
|
+
group: release-${{ github.ref }}
|
|
24
|
+
cancel-in-progress: false
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
validate:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
outputs:
|
|
30
|
+
tag_name: ${{ steps.meta.outputs.tag_name }}
|
|
31
|
+
version_tag: ${{ steps.meta.outputs.version_tag }}
|
|
32
|
+
publish_target: ${{ steps.meta.outputs.publish_target }}
|
|
33
|
+
steps:
|
|
34
|
+
- uses: actions/checkout@v4
|
|
35
|
+
with:
|
|
36
|
+
fetch-depth: 0
|
|
37
|
+
|
|
38
|
+
- name: Determine publish target
|
|
39
|
+
id: meta
|
|
40
|
+
shell: bash
|
|
41
|
+
run: |
|
|
42
|
+
set -euo pipefail
|
|
43
|
+
|
|
44
|
+
# For tag pushes, always publish to PyPI.
|
|
45
|
+
if [[ "${GITHUB_EVENT_NAME}" == "push" && "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
|
46
|
+
echo "publish_target=pypi" >> "$GITHUB_OUTPUT"
|
|
47
|
+
else
|
|
48
|
+
echo "publish_target=${{ inputs.target }}" >> "$GITHUB_OUTPUT"
|
|
49
|
+
fi
|
|
50
|
+
|
|
51
|
+
echo "tag_name=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT"
|
|
52
|
+
if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
|
|
53
|
+
if [[ "${GITHUB_REF_NAME}" != v* ]]; then
|
|
54
|
+
echo "Expected tag to start with 'v' (got: ${GITHUB_REF_NAME})" >&2
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
echo "version_tag=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
|
|
58
|
+
else
|
|
59
|
+
echo "version_tag=" >> "$GITHUB_OUTPUT"
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
- name: Require tag ref for publishing
|
|
63
|
+
if: ${{ steps.meta.outputs.publish_target == 'pypi' && github.ref_type != 'tag' }}
|
|
64
|
+
shell: bash
|
|
65
|
+
run: |
|
|
66
|
+
echo "Publishing requires running the workflow on a tag ref (vX.Y.Z)." >&2
|
|
67
|
+
exit 1
|
|
68
|
+
|
|
69
|
+
- name: Set up Python
|
|
70
|
+
uses: actions/setup-python@v5
|
|
71
|
+
with:
|
|
72
|
+
python-version: "3.12"
|
|
73
|
+
|
|
74
|
+
- name: Validate tag matches pyproject version
|
|
75
|
+
if: ${{ github.ref_type == 'tag' }}
|
|
76
|
+
shell: bash
|
|
77
|
+
run: |
|
|
78
|
+
set -euo pipefail
|
|
79
|
+
PYPROJECT_VERSION="$(python -c "import tomllib, pathlib; d=tomllib.loads(pathlib.Path('pyproject.toml').read_text()); print(d['project']['version'])")"
|
|
80
|
+
TAG_VERSION="${{ steps.meta.outputs.version_tag }}"
|
|
81
|
+
if [[ "${PYPROJECT_VERSION}" != "${TAG_VERSION}" ]]; then
|
|
82
|
+
echo "Version mismatch: pyproject.toml=${PYPROJECT_VERSION} tag=${TAG_VERSION}" >&2
|
|
83
|
+
exit 1
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
- name: Validate tag is on main
|
|
87
|
+
if: ${{ github.ref_type == 'tag' }}
|
|
88
|
+
shell: bash
|
|
89
|
+
run: |
|
|
90
|
+
set -euo pipefail
|
|
91
|
+
git fetch origin main --depth=1
|
|
92
|
+
git merge-base --is-ancestor "${GITHUB_SHA}" "origin/main"
|
|
93
|
+
|
|
94
|
+
test:
|
|
95
|
+
runs-on: ubuntu-latest
|
|
96
|
+
needs: validate
|
|
97
|
+
steps:
|
|
98
|
+
- uses: actions/checkout@v4
|
|
99
|
+
with:
|
|
100
|
+
fetch-depth: 0
|
|
101
|
+
|
|
102
|
+
- name: Set up Python
|
|
103
|
+
uses: actions/setup-python@v5
|
|
104
|
+
with:
|
|
105
|
+
python-version: "3.12"
|
|
106
|
+
cache: pip
|
|
107
|
+
cache-dependency-path: pyproject.toml
|
|
108
|
+
|
|
109
|
+
- name: Install
|
|
110
|
+
run: |
|
|
111
|
+
python -m pip install --upgrade pip
|
|
112
|
+
python -m pip install -e ".[dev]"
|
|
113
|
+
|
|
114
|
+
- name: Lint
|
|
115
|
+
run: |
|
|
116
|
+
ruff format --check .
|
|
117
|
+
ruff check .
|
|
118
|
+
|
|
119
|
+
- name: Type check
|
|
120
|
+
run: |
|
|
121
|
+
mypy affinity
|
|
122
|
+
|
|
123
|
+
- name: Test
|
|
124
|
+
run: |
|
|
125
|
+
pytest
|
|
126
|
+
|
|
127
|
+
build:
|
|
128
|
+
runs-on: ubuntu-latest
|
|
129
|
+
needs: [validate, test]
|
|
130
|
+
steps:
|
|
131
|
+
- uses: actions/checkout@v4
|
|
132
|
+
with:
|
|
133
|
+
fetch-depth: 0
|
|
134
|
+
|
|
135
|
+
- name: Set up Python
|
|
136
|
+
uses: actions/setup-python@v5
|
|
137
|
+
with:
|
|
138
|
+
python-version: "3.12"
|
|
139
|
+
cache: pip
|
|
140
|
+
cache-dependency-path: pyproject.toml
|
|
141
|
+
|
|
142
|
+
- name: Build distributions
|
|
143
|
+
run: |
|
|
144
|
+
python -m pip install --upgrade pip
|
|
145
|
+
python -m pip install build
|
|
146
|
+
python -m build
|
|
147
|
+
|
|
148
|
+
- name: Upload dist artifacts
|
|
149
|
+
uses: actions/upload-artifact@v4
|
|
150
|
+
with:
|
|
151
|
+
name: dist-${{ needs.validate.outputs.tag_name }}
|
|
152
|
+
path: dist/
|
|
153
|
+
if-no-files-found: error
|
|
154
|
+
|
|
155
|
+
publish:
|
|
156
|
+
runs-on: ubuntu-latest
|
|
157
|
+
needs: [validate, build]
|
|
158
|
+
if: ${{ needs.validate.outputs.publish_target != 'none' }}
|
|
159
|
+
environment: ${{ needs.validate.outputs.publish_target }}
|
|
160
|
+
steps:
|
|
161
|
+
- name: Download dist artifacts
|
|
162
|
+
uses: actions/download-artifact@v4
|
|
163
|
+
with:
|
|
164
|
+
name: dist-${{ needs.validate.outputs.tag_name }}
|
|
165
|
+
path: dist/
|
|
166
|
+
|
|
167
|
+
- name: Publish to PyPI (trusted publishing)
|
|
168
|
+
if: ${{ needs.validate.outputs.publish_target == 'pypi' }}
|
|
169
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
170
|
+
with:
|
|
171
|
+
attestations: true
|
|
172
|
+
|
|
173
|
+
- name: Publish to TestPyPI (trusted publishing)
|
|
174
|
+
if: ${{ needs.validate.outputs.publish_target == 'testpypi' }}
|
|
175
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
176
|
+
with:
|
|
177
|
+
repository-url: https://test.pypi.org/legacy/
|
|
178
|
+
attestations: true
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# OS
|
|
2
|
+
.DS_Store
|
|
3
|
+
Thumbs.db
|
|
4
|
+
|
|
5
|
+
# Python
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*.so
|
|
9
|
+
*.egg
|
|
10
|
+
*.whl
|
|
11
|
+
*.egg-info/
|
|
12
|
+
.eggs/
|
|
13
|
+
build/
|
|
14
|
+
dist/
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.hypothesis/
|
|
19
|
+
.tox/
|
|
20
|
+
.nox/
|
|
21
|
+
.coverage
|
|
22
|
+
.coverage.*
|
|
23
|
+
coverage.xml
|
|
24
|
+
htmlcov/
|
|
25
|
+
|
|
26
|
+
# Virtual environments
|
|
27
|
+
.venv/
|
|
28
|
+
venv/
|
|
29
|
+
ENV/
|
|
30
|
+
.env
|
|
31
|
+
.env.*
|
|
32
|
+
!.env.example
|
|
33
|
+
!.env.sample
|
|
34
|
+
!.env.template
|
|
35
|
+
!.env.dist
|
|
36
|
+
|
|
37
|
+
# Tooling caches
|
|
38
|
+
.cache/
|
|
39
|
+
.hatch/
|
|
40
|
+
.hatch_cache/
|
|
41
|
+
.mkdocs_cache/
|
|
42
|
+
site/
|
|
43
|
+
.direnv/
|
|
44
|
+
.envrc
|
|
45
|
+
*.log
|
|
46
|
+
.ipynb_checkpoints/
|
|
47
|
+
|
|
48
|
+
# IDEs
|
|
49
|
+
.vscode/
|
|
50
|
+
.idea/
|
|
51
|
+
*.iml
|
|
52
|
+
|
|
53
|
+
# Internal (not for publishing)
|
|
54
|
+
docs/internal/
|
|
55
|
+
.cursorrules
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
3
|
+
rev: v6.0.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: check-added-large-files
|
|
6
|
+
- id: check-ast
|
|
7
|
+
- id: check-case-conflict
|
|
8
|
+
- id: check-merge-conflict
|
|
9
|
+
- id: check-toml
|
|
10
|
+
- id: check-yaml
|
|
11
|
+
- id: end-of-file-fixer
|
|
12
|
+
- id: mixed-line-ending
|
|
13
|
+
- id: trailing-whitespace
|
|
14
|
+
|
|
15
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
16
|
+
rev: v0.14.9
|
|
17
|
+
hooks:
|
|
18
|
+
- id: ruff-check
|
|
19
|
+
args: [--fix]
|
|
20
|
+
- id: ruff-format
|
|
21
|
+
|
|
22
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
23
|
+
rev: v1.10.0
|
|
24
|
+
hooks:
|
|
25
|
+
- id: mypy
|
|
26
|
+
pass_filenames: false
|
|
27
|
+
args: [affinity]
|
|
28
|
+
additional_dependencies:
|
|
29
|
+
- httpx>=0.25.0
|
|
30
|
+
- pydantic>=2.0.0
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
[Unreleased]: https://github.com/yaniv-golan/affinity-sdk/compare/HEAD...HEAD
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- `client.files.download_stream(...)` and `client.files.download_to(...)` for chunked file downloads.
|
|
13
|
+
- `client.files.upload_path(...)` and `client.files.upload_bytes(...)` for ergonomic uploads.
|
|
14
|
+
- `client.files.all(...)` / `client.files.iter(...)` for auto-pagination over files.
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- File downloads now follow redirects without forwarding credentials and use the standard retry/diagnostics policy.
|
|
18
|
+
- `client.files.list(...)` and `client.files.upload(...)` now require exactly one of `person_id`, `organization_id`, or `opportunity_id` (per API contract).
|