diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6cf64f0..73a73ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ['3.11', '3.12', '3.13', '3.14'] + python-version: ['3.11', '3.12', '3.13', '3.14', '3.15'] steps: - uses: actions/checkout@v4 - uses: astral-sh/setup-uv@v5 @@ -34,7 +34,7 @@ jobs: matrix: include: - resolution: highest - python-version: '3.14' + python-version: '3.15' - resolution: lowest-direct python-version: '3.11' steps: @@ -47,17 +47,3 @@ jobs: - run: uv run --no-sync pytest packages/discolike-cli/tests -q - run: uv build --all-packages -o dist - run: uv run --no-project --isolated --resolution ${{ matrix.resolution }} --find-links dist --with dist/discolike_cli-*.whl discolike --version - - # 3.15 is still prerelease; non-blocking until 3.15.0 final, when it moves - # into the matrix above and gets a classifier. - test-prerelease: - runs-on: ubuntu-latest - continue-on-error: true - steps: - - uses: actions/checkout@v4 - - uses: astral-sh/setup-uv@v5 - with: - python-version: '3.15' - - run: uv sync --all-packages - - run: uv run pytest packages/discolike/tests -q - - run: uv run pytest packages/discolike-cli/tests -q diff --git a/CHANGELOG.md b/CHANGELOG.md index 355cde2..de9e3a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ # Changelog -## Unreleased +## 0.6.2 (2026-10-21) +- SDK/CLI: Python 3.15 is supported and tested in CI. - SDK/CLI: an LLM integration's `model_name` can carry provider settings after `#`, as URL query parameters: `region` for `bedrock` and `bedrock_mantle` (any AWS region, optional), `account` for `snowflake` (account identifier, with a programmatic access token as `api_key`) and `region` plus `project` for `watsonx`, e.g. `us.anthropic.claude-sonnet-4-5-20250929-v1:0#region=us-east-1`. Snowflake and watsonx become usable as providers. An unknown setting or region is a 400 (`ValidationError`). `DiscogenModels.provider_regions` lists the accepted regions per provider. The CLI's `llm-providers create`, `update` and `test-connection` gain `--region`, `--account` and `--project`, which build the suffix for you, and `discogen models` output gains a `provider_regions` key. It needs an API release that knows the settings; older SDKs can already send the suffix in `model_name`. +- SDK: `BulkContactMatchQueryItem` gains `linkedin`, a LinkedIn profile URL or username matched exactly before `email`, then name and company, so a list of profile URLs alone returns the matching contacts. It needs an API release that knows the field. +- SDK (note for maintainers): `discolike/_generated/requests.py` is regenerated from the dev spec, which adds `linkedin` and moves `api_key` after `base_url` on the LLM provider request models (keyword arguments, so no caller change). ## 0.6.1 (2026-10-19) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eae594e..4afdc31 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -24,7 +24,7 @@ uv run pytest packages/discolike/tests -q uv run pytest packages/discolike-cli/tests -q ``` -CI runs the same checks across Python 3.11–3.14. +CI runs the same checks across Python 3.11–3.15. ## Branches diff --git a/examples/discover_and_enrich.py b/examples/discover_and_enrich.py index 6cdff84..6f6447c 100644 --- a/examples/discover_and_enrich.py +++ b/examples/discover_and_enrich.py @@ -54,7 +54,7 @@ def main() -> None: print(f"\nRunning DiscoGen over {len(domains)} domains: {args.query!r}") job = client.discogen.process(DiscoGenProcessRequest(query=args.query, domains=domains, web_search=True)) - status = job.wait(timeout=args.timeout, on_poll=lambda s: print(f" status={s.status} progress={s.progress}%")) + status = job.wait(max_wait=args.timeout, on_poll=lambda s: print(f" status={s.status} progress={s.progress}%")) print("\nEnriched results:") for row in status.results or []: diff --git a/examples/enrich_crm_export.py b/examples/enrich_crm_export.py index 6322a9f..e30406f 100644 --- a/examples/enrich_crm_export.py +++ b/examples/enrich_crm_export.py @@ -47,9 +47,9 @@ def enrich_row(client: Discolike, *, domain: str) -> dict[str, str]: "dl_name": profile.name or "", "dl_employees": profile.employees or "", "dl_revenue_range": profile.revenue_range or "", - "dl_country": address.country if address else "", - "dl_state": address.state if address else "", - "dl_city": address.city if address else "", + "dl_country": (address.country if address else None) or "", + "dl_state": (address.state if address else None) or "", + "dl_city": (address.city if address else None) or "", "dl_industry_groups": top_keys(profile.industry_groups), "dl_business_model": top_keys(profile.business_model), "dl_description": profile.description or "", diff --git a/examples/find_emails_from_csv.py b/examples/find_emails_from_csv.py index 228ca6b..930e71b 100644 --- a/examples/find_emails_from_csv.py +++ b/examples/find_emails_from_csv.py @@ -68,7 +68,7 @@ def main() -> None: chunk = contacts[start : start + MAX_CONTACTS_PER_BATCH] print(f"Submitting batch of {len(chunk)} contacts ({start + len(chunk)}/{len(contacts)})...") batch = client.email.find_batch(FindEmailBatchRequest.model_validate({"requests": chunk})) - results = batch.results(timeout=args.timeout) + results = batch.results(max_wait=args.timeout) for item in results.results: output = item.result if not isinstance(output, EnumerationOutput): diff --git a/examples/match_crm_contacts.py b/examples/match_crm_contacts.py index 55fa8e4..dd49a2f 100644 --- a/examples/match_crm_contacts.py +++ b/examples/match_crm_contacts.py @@ -208,7 +208,7 @@ def main() -> None: job = client.contacts.bulk_match( BulkContactMatchRequest.model_validate({"queries": queries, "limit": 1}) ) - status = job.wait(timeout=args.timeout) + status = job.wait(max_wait=args.timeout) except Exception as exc: # leave the chunk un-checkpointed so a rerun retries it failed_chunks += 1 print(f" ! {label} failed ({exc}); rows left pending, rerun to retry") diff --git a/packages/discolike-cli/pyproject.toml b/packages/discolike-cli/pyproject.toml index c25eae5..23b9182 100644 --- a/packages/discolike-cli/pyproject.toml +++ b/packages/discolike-cli/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "discolike-cli" -version = "0.6.1" +version = "0.6.2" description = "Official CLI for the DiscoLike API" readme = "README.md" license = "MIT" @@ -12,7 +12,7 @@ license-files = ["LICENSE"] requires-python = ">=3.11" authors = [{ name = "DiscoLike", email = "support@discolike.com" }] dependencies = [ - "discolike==0.6.1", + "discolike==0.6.2", "typer>=0.26.1,<0.28", "rich>=13.0", ] @@ -25,6 +25,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Programming Language :: Python :: 3 :: Only", "Operating System :: OS Independent", "Environment :: Console", diff --git a/packages/discolike/pyproject.toml b/packages/discolike/pyproject.toml index 507ad99..0223fa3 100644 --- a/packages/discolike/pyproject.toml +++ b/packages/discolike/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", + "Programming Language :: Python :: 3.15", "Programming Language :: Python :: 3 :: Only", "Operating System :: OS Independent", "Topic :: Software Development :: Libraries :: Python Modules", @@ -33,7 +34,7 @@ classifiers = [ ] [project.optional-dependencies] -cli = ["discolike-cli==0.6.1"] +cli = ["discolike-cli==0.6.2"] [project.urls] Homepage = "https://www.discolike.com" diff --git a/packages/discolike/src/discolike/_generated/requests.py b/packages/discolike/src/discolike/_generated/requests.py index a519c7d..3749f6b 100644 --- a/packages/discolike/src/discolike/_generated/requests.py +++ b/packages/discolike/src/discolike/_generated/requests.py @@ -2905,7 +2905,6 @@ class LLMProviderCreateRequest(DiscolikeRequest): title="Provider", ), ] - api_key: Annotated[str, Field(description="API key for the provider", title="Api Key")] model_name: Annotated[ str, Field(description="Default model name for this integration", title="Model Name"), @@ -2917,6 +2916,7 @@ class LLMProviderCreateRequest(DiscolikeRequest): title="Base Url", ), ] = None + api_key: Annotated[str, Field(description="API key for the provider", title="Api Key")] class LLMProviderUpdateRequest(DiscolikeRequest): @@ -2934,13 +2934,6 @@ class LLMProviderUpdateRequest(DiscolikeRequest): title="Provider", ), ] - api_key: Annotated[ - str | None, - Field( - description="API key for the provider (null to keep existing)", - title="Api Key", - ), - ] model_name: Annotated[ str, Field(description="Default model name for this integration", title="Model Name"), @@ -2952,6 +2945,13 @@ class LLMProviderUpdateRequest(DiscolikeRequest): title="Base Url", ), ] = None + api_key: Annotated[ + str | None, + Field( + description="API key for the provider (null to keep existing)", + title="Api Key", + ), + ] class SearchProviderRequest(DiscolikeRequest): @@ -3084,7 +3084,7 @@ class BulkContactMatchQueryItem(DiscolikeRequest): name: Annotated[ str | None, Field( - description="Person name to search for. Required unless email is provided.", + description="Person name to search for. Required unless email or linkedin is provided.", title="Name", ), ] = None @@ -3095,6 +3095,13 @@ class BulkContactMatchQueryItem(DiscolikeRequest): title="Email", ), ] = None + linkedin: Annotated[ + str | None, + Field( + description="LinkedIn profile URL or username for exact lookup, tried before email. When found, email and name/company matching are skipped for this row.", + title="Linkedin", + ), + ] = None company_name: Annotated[ str | None, Field(description="Company name to narrow the search.", title="Company Name"), diff --git a/packages/discolike/src/discolike/_version.py b/packages/discolike/src/discolike/_version.py index 43c4ab0..22049ab 100644 --- a/packages/discolike/src/discolike/_version.py +++ b/packages/discolike/src/discolike/_version.py @@ -1 +1 @@ -__version__ = "0.6.1" +__version__ = "0.6.2" diff --git a/packages/discolike/tests/test_package.py b/packages/discolike/tests/test_package.py index afc8344..9f746fc 100644 --- a/packages/discolike/tests/test_package.py +++ b/packages/discolike/tests/test_package.py @@ -2,4 +2,4 @@ def test_version() -> None: - assert discolike.__version__ == "0.6.1" + assert discolike.__version__ == "0.6.2" diff --git a/uv.lock b/uv.lock index 38b08de..50ba2dd 100644 --- a/uv.lock +++ b/uv.lock @@ -343,7 +343,7 @@ dev = [ [[package]] name = "discolike-cli" -version = "0.6.1" +version = "0.6.2" source = { editable = "packages/discolike-cli" } dependencies = [ { name = "discolike" },