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.
Files changed (115) hide show
  1. affinity_sdk-0.2.0/.editorconfig +19 -0
  2. affinity_sdk-0.2.0/.env.example +3 -0
  3. affinity_sdk-0.2.0/.gitattributes +7 -0
  4. affinity_sdk-0.2.0/.github/ISSUE_TEMPLATE/bug_report.yml +44 -0
  5. affinity_sdk-0.2.0/.github/ISSUE_TEMPLATE/feature_request.yml +27 -0
  6. affinity_sdk-0.2.0/.github/dependabot.yml +12 -0
  7. affinity_sdk-0.2.0/.github/pull_request_template.md +14 -0
  8. affinity_sdk-0.2.0/.github/workflows/ci.yml +56 -0
  9. affinity_sdk-0.2.0/.github/workflows/docs.yml +97 -0
  10. affinity_sdk-0.2.0/.github/workflows/linkcheck.yml +44 -0
  11. affinity_sdk-0.2.0/.github/workflows/openapi-validation.yml +30 -0
  12. affinity_sdk-0.2.0/.github/workflows/release.yml +178 -0
  13. affinity_sdk-0.2.0/.gitignore +55 -0
  14. affinity_sdk-0.2.0/.pre-commit-config.yaml +30 -0
  15. affinity_sdk-0.2.0/CHANGELOG.md +18 -0
  16. affinity_sdk-0.2.0/CODE_OF_CONDUCT.md +96 -0
  17. affinity_sdk-0.2.0/CONTRIBUTING.md +60 -0
  18. affinity_sdk-0.2.0/LICENSE +21 -0
  19. affinity_sdk-0.2.0/PKG-INFO +538 -0
  20. affinity_sdk-0.2.0/README.md +494 -0
  21. affinity_sdk-0.2.0/SECURITY.md +10 -0
  22. affinity_sdk-0.2.0/affinity/__init__.py +100 -0
  23. affinity_sdk-0.2.0/affinity/client.py +517 -0
  24. affinity_sdk-0.2.0/affinity/clients/__init__.py +19 -0
  25. affinity_sdk-0.2.0/affinity/clients/http.py +1717 -0
  26. affinity_sdk-0.2.0/affinity/exceptions.py +445 -0
  27. affinity_sdk-0.2.0/affinity/filters.py +290 -0
  28. affinity_sdk-0.2.0/affinity/hooks.py +17 -0
  29. affinity_sdk-0.2.0/affinity/models/__init__.py +152 -0
  30. affinity_sdk-0.2.0/affinity/models/entities.py +579 -0
  31. affinity_sdk-0.2.0/affinity/models/pagination.py +245 -0
  32. affinity_sdk-0.2.0/affinity/models/secondary.py +387 -0
  33. affinity_sdk-0.2.0/affinity/models/types.py +425 -0
  34. affinity_sdk-0.2.0/affinity/progress.py +22 -0
  35. affinity_sdk-0.2.0/affinity/py.typed +0 -0
  36. affinity_sdk-0.2.0/affinity/services/__init__.py +38 -0
  37. affinity_sdk-0.2.0/affinity/services/companies.py +532 -0
  38. affinity_sdk-0.2.0/affinity/services/lists.py +761 -0
  39. affinity_sdk-0.2.0/affinity/services/opportunities.py +306 -0
  40. affinity_sdk-0.2.0/affinity/services/persons.py +517 -0
  41. affinity_sdk-0.2.0/affinity/services/tasks.py +193 -0
  42. affinity_sdk-0.2.0/affinity/services/v1_only.py +1010 -0
  43. affinity_sdk-0.2.0/affinity/types.py +73 -0
  44. affinity_sdk-0.2.0/docs/public/changelog.md +3 -0
  45. affinity_sdk-0.2.0/docs/public/examples.md +33 -0
  46. affinity_sdk-0.2.0/docs/public/getting-started.md +90 -0
  47. affinity_sdk-0.2.0/docs/public/glossary.md +22 -0
  48. affinity_sdk-0.2.0/docs/public/guides/api-versions-and-routing.md +46 -0
  49. affinity_sdk-0.2.0/docs/public/guides/authentication.md +29 -0
  50. affinity_sdk-0.2.0/docs/public/guides/configuration.md +122 -0
  51. affinity_sdk-0.2.0/docs/public/guides/debugging-hooks.md +22 -0
  52. affinity_sdk-0.2.0/docs/public/guides/errors-and-retries.md +81 -0
  53. affinity_sdk-0.2.0/docs/public/guides/field-types-and-values.md +67 -0
  54. affinity_sdk-0.2.0/docs/public/guides/filtering.md +39 -0
  55. affinity_sdk-0.2.0/docs/public/guides/ids-and-types.md +21 -0
  56. affinity_sdk-0.2.0/docs/public/guides/models.md +41 -0
  57. affinity_sdk-0.2.0/docs/public/guides/pagination.md +23 -0
  58. affinity_sdk-0.2.0/docs/public/guides/rate-limits.md +34 -0
  59. affinity_sdk-0.2.0/docs/public/guides/sync-vs-async.md +55 -0
  60. affinity_sdk-0.2.0/docs/public/guides/v1-v2-routing.md +3 -0
  61. affinity_sdk-0.2.0/docs/public/guides/webhooks.md +59 -0
  62. affinity_sdk-0.2.0/docs/public/index.md +31 -0
  63. affinity_sdk-0.2.0/docs/public/reference/client.md +9 -0
  64. affinity_sdk-0.2.0/docs/public/reference/exceptions.md +3 -0
  65. affinity_sdk-0.2.0/docs/public/reference/filters.md +3 -0
  66. affinity_sdk-0.2.0/docs/public/reference/models.md +3 -0
  67. affinity_sdk-0.2.0/docs/public/reference/services/companies.md +5 -0
  68. affinity_sdk-0.2.0/docs/public/reference/services/lists.md +5 -0
  69. affinity_sdk-0.2.0/docs/public/reference/services/opportunities.md +5 -0
  70. affinity_sdk-0.2.0/docs/public/reference/services/persons.md +5 -0
  71. affinity_sdk-0.2.0/docs/public/reference/services/tasks.md +5 -0
  72. affinity_sdk-0.2.0/docs/public/reference/services/v1/auth.md +3 -0
  73. affinity_sdk-0.2.0/docs/public/reference/services/v1/field-values.md +3 -0
  74. affinity_sdk-0.2.0/docs/public/reference/services/v1/fields.md +3 -0
  75. affinity_sdk-0.2.0/docs/public/reference/services/v1/files.md +3 -0
  76. affinity_sdk-0.2.0/docs/public/reference/services/v1/interactions.md +3 -0
  77. affinity_sdk-0.2.0/docs/public/reference/services/v1/notes.md +3 -0
  78. affinity_sdk-0.2.0/docs/public/reference/services/v1/relationships.md +3 -0
  79. affinity_sdk-0.2.0/docs/public/reference/services/v1/reminders.md +3 -0
  80. affinity_sdk-0.2.0/docs/public/reference/services/v1/webhooks.md +3 -0
  81. affinity_sdk-0.2.0/docs/public/reference/types.md +3 -0
  82. affinity_sdk-0.2.0/docs/public/troubleshooting.md +22 -0
  83. affinity_sdk-0.2.0/examples/advanced_usage.py +476 -0
  84. affinity_sdk-0.2.0/examples/async_lifecycle.py +43 -0
  85. affinity_sdk-0.2.0/examples/basic_usage.py +72 -0
  86. affinity_sdk-0.2.0/examples/filter_builder.py +36 -0
  87. affinity_sdk-0.2.0/examples/hooks_debugging.py +40 -0
  88. affinity_sdk-0.2.0/examples/list_management.py +120 -0
  89. affinity_sdk-0.2.0/examples/resolve_helpers.py +38 -0
  90. affinity_sdk-0.2.0/examples/task_polling.py +34 -0
  91. affinity_sdk-0.2.0/mkdocs.yml +75 -0
  92. affinity_sdk-0.2.0/pyproject.toml +159 -0
  93. affinity_sdk-0.2.0/tests/conftest.py +180 -0
  94. affinity_sdk-0.2.0/tests/test_affinity_client_wrapper_additional_coverage.py +57 -0
  95. affinity_sdk-0.2.0/tests/test_client.py +1163 -0
  96. affinity_sdk-0.2.0/tests/test_env_helpers.py +51 -0
  97. affinity_sdk-0.2.0/tests/test_file_download_streaming.py +154 -0
  98. affinity_sdk-0.2.0/tests/test_file_upload_helpers_and_validation.py +91 -0
  99. affinity_sdk-0.2.0/tests/test_http_client_additional_coverage.py +401 -0
  100. affinity_sdk-0.2.0/tests/test_http_client_remaining_coverage.py +1505 -0
  101. affinity_sdk-0.2.0/tests/test_integration_smoke.py +36 -0
  102. affinity_sdk-0.2.0/tests/test_interactions_and_files_regressions.py +196 -0
  103. affinity_sdk-0.2.0/tests/test_list_entry_membership_and_opportunities.py +209 -0
  104. affinity_sdk-0.2.0/tests/test_models.py +660 -0
  105. affinity_sdk-0.2.0/tests/test_new_features.py +712 -0
  106. affinity_sdk-0.2.0/tests/test_pagination_iterators.py +122 -0
  107. affinity_sdk-0.2.0/tests/test_requirements_additional.py +211 -0
  108. affinity_sdk-0.2.0/tests/test_services_lists_additional_coverage.py +682 -0
  109. affinity_sdk-0.2.0/tests/test_services_opportunities_tasks_additional_coverage.py +386 -0
  110. affinity_sdk-0.2.0/tests/test_services_persons_companies_additional_coverage.py +944 -0
  111. affinity_sdk-0.2.0/tests/test_small_modules_coverage.py +173 -0
  112. affinity_sdk-0.2.0/tests/test_v1_only_services_additional_coverage.py +491 -0
  113. affinity_sdk-0.2.0/tests/test_v1_only_services_more_coverage.py +585 -0
  114. affinity_sdk-0.2.0/tools/generate_requirements_mapping.py +140 -0
  115. 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,3 @@
1
+ # Copy this file to `.env` and set your real key.
2
+ # Never commit `.env` (it is gitignored).
3
+ AFFINITY_API_KEY=
@@ -0,0 +1,7 @@
1
+ * text=auto eol=lf
2
+
3
+ *.png binary
4
+ *.jpg binary
5
+ *.jpeg binary
6
+ *.gif binary
7
+ *.webp binary
@@ -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,12 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 10
8
+
9
+ - package-ecosystem: "github-actions"
10
+ directory: "/"
11
+ schedule:
12
+ interval: "weekly"
@@ -0,0 +1,14 @@
1
+ ## Summary
2
+
3
+ -
4
+
5
+ ## Test plan
6
+
7
+ - [ ] Added/updated tests
8
+ - [ ] `pytest`
9
+ - [ ] `ruff check .`
10
+ - [ ] `mypy affinity`
11
+
12
+ ## Notes
13
+
14
+ -
@@ -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).