From 0cf0ebbe3b52ba080bac1adc8039cfd73f245b6f Mon Sep 17 00:00:00 2001 From: Evan Sosenko Date: Tue, 18 Aug 2026 16:14:55 -0700 Subject: [PATCH] feat: support boolean literal constraints --- codegen/layouts/resource.hbs | 2 +- codegen/layouts/route.hbs | 2 +- codegen/lib/layouts/resources.ts | 13 +++++++ codegen/lib/python-type.ts | 13 +++++++ package-lock.json | 8 ++--- package.json | 2 +- seam/resources/access_code.py | 8 ++--- seam/resources/access_grant.py | 2 +- seam/resources/access_method.py | 2 +- seam/resources/acs_access_group.py | 4 +-- seam/resources/acs_credential.py | 4 +-- seam/resources/acs_encoder.py | 2 +- seam/resources/acs_entrance.py | 2 +- seam/resources/acs_system.py | 2 +- seam/resources/acs_user.py | 4 +-- seam/resources/action_attempt.py | 6 ++-- seam/resources/batch.py | 2 +- seam/resources/client_session.py | 2 +- seam/resources/connect_webview.py | 2 +- seam/resources/connected_account.py | 2 +- seam/resources/customer_portal.py | 2 +- seam/resources/device.py | 10 +++--- seam/resources/device_provider.py | 2 +- seam/resources/instant_key.py | 2 +- seam/resources/noise_threshold.py | 2 +- seam/resources/pagination.py | 2 +- seam/resources/phone.py | 2 +- seam/resources/seam_event.py | 2 +- seam/resources/space.py | 2 +- seam/resources/thermostat_daily_program.py | 2 +- seam/resources/thermostat_schedule.py | 2 +- seam/resources/unmanaged_access_code.py | 12 +++---- seam/resources/unmanaged_access_grant.py | 2 +- seam/resources/unmanaged_access_method.py | 2 +- seam/resources/unmanaged_device.py | 6 ++-- seam/resources/unmanaged_user_identity.py | 2 +- seam/resources/user_identity.py | 2 +- seam/resources/webhook.py | 2 +- seam/resources/workspace.py | 2 +- seam/routes/access_codes.py | 2 +- seam/routes/access_codes_simulate.py | 2 +- seam/routes/access_codes_unmanaged.py | 2 +- seam/routes/access_grants.py | 2 +- seam/routes/access_grants_unmanaged.py | 6 ++-- seam/routes/access_methods.py | 2 +- seam/routes/access_methods_unmanaged.py | 2 +- seam/routes/acs.py | 2 +- seam/routes/acs_access_groups.py | 2 +- seam/routes/acs_credentials.py | 2 +- seam/routes/acs_encoders.py | 2 +- seam/routes/acs_encoders_simulate.py | 2 +- seam/routes/acs_entrances.py | 2 +- seam/routes/acs_systems.py | 2 +- seam/routes/acs_users.py | 2 +- seam/routes/action_attempts.py | 2 +- seam/routes/client_sessions.py | 2 +- seam/routes/connect_webviews.py | 2 +- seam/routes/connected_accounts.py | 2 +- seam/routes/connected_accounts_simulate.py | 2 +- seam/routes/customers.py | 2 +- seam/routes/devices.py | 2 +- seam/routes/devices_simulate.py | 2 +- seam/routes/devices_unmanaged.py | 6 ++-- seam/routes/events.py | 2 +- seam/routes/instant_keys.py | 2 +- seam/routes/locks.py | 2 +- seam/routes/locks_simulate.py | 2 +- seam/routes/noise_sensors.py | 2 +- seam/routes/noise_sensors_noise_thresholds.py | 2 +- seam/routes/noise_sensors_simulate.py | 2 +- seam/routes/phones.py | 2 +- seam/routes/phones_simulate.py | 2 +- seam/routes/spaces.py | 2 +- seam/routes/thermostats.py | 2 +- seam/routes/thermostats_daily_programs.py | 2 +- seam/routes/thermostats_schedules.py | 2 +- seam/routes/thermostats_simulate.py | 2 +- seam/routes/user_identities.py | 2 +- seam/routes/user_identities_unmanaged.py | 6 ++-- seam/routes/webhooks.py | 2 +- seam/routes/workspaces.py | 2 +- test/resource_types_test.py | 35 +++++++++++++++++++ 82 files changed, 168 insertions(+), 107 deletions(-) create mode 100644 test/resource_types_test.py diff --git a/codegen/layouts/resource.hbs b/codegen/layouts/resource.hbs index 539c4ed1..40da5595 100644 --- a/codegen/layouts/resource.hbs +++ b/codegen/layouts/resource.hbs @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/codegen/layouts/route.hbs b/codegen/layouts/route.hbs index 32540f82..075e746c 100644 --- a/codegen/layouts/route.hbs +++ b/codegen/layouts/route.hbs @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/codegen/lib/layouts/resources.ts b/codegen/lib/layouts/resources.ts index fc4d6397..8b226386 100644 --- a/codegen/lib/layouts/resources.ts +++ b/codegen/lib/layouts/resources.ts @@ -107,6 +107,19 @@ const mergeOccurrences = (occurrences: Property[], path: string): Property => { ) } + if (first.format === 'boolean') { + const booleans = occurrences as Array< + Extract + > + const values = booleans.some(({ values }) => values == null) + ? undefined + : [...new Set(booleans.flatMap(({ values }) => values ?? []))] + const merged = { ...first, ...docs } + if (values == null) delete merged.values + else merged.values = values + return merged + } + if (first.format === 'object') { return { ...first, diff --git a/codegen/lib/python-type.ts b/codegen/lib/python-type.ts index fadcd5d7..83b2e965 100644 --- a/codegen/lib/python-type.ts +++ b/codegen/lib/python-type.ts @@ -18,6 +18,10 @@ export const mapParameterToPythonType = (parameter: Parameter): string => { return parameter.isInt ? 'int' : 'float' } + if (parameter.format === 'boolean') { + return mapBooleanToPythonType(parameter.values) + } + return mapScalarFormatToPythonType(parameter.format) } @@ -51,6 +55,10 @@ export const mapRequiredPropertyToPythonType = ( return property.isInt ? 'int' : 'float' } + if (property.format === 'boolean') { + return mapBooleanToPythonType(property.values) + } + // Batch resource properties are lists of the named resource on the wire, // though the blueprint types them as records. if (property.format === 'record' && 'resourceType' in property) { @@ -64,6 +72,11 @@ export const mapRequiredPropertyToPythonType = ( return mapScalarFormatToPythonType(property.format) } +const mapBooleanToPythonType = (values?: boolean[]): string => + values == null || values.length === 0 + ? 'bool' + : `Literal[${values.map((value) => (value ? 'True' : 'False')).join(', ')}]` + const mapScalarFormatToPythonType = (format: ScalarFormat): string => { switch (format) { case 'string': diff --git a/package-lock.json b/package-lock.json index 3e6a6f45..322e2d7b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "": { "name": "@seamapi/python", "devDependencies": { - "@seamapi/blueprint": "^1.5.1", + "@seamapi/blueprint": "^1.6.0", "@seamapi/fake-seam-connect": "1.86.0", "@seamapi/smith": "^1.1.0", "@seamapi/types": "1.1001.0", @@ -787,9 +787,9 @@ "license": "MIT" }, "node_modules/@seamapi/blueprint": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@seamapi/blueprint/-/blueprint-1.5.1.tgz", - "integrity": "sha512-rXHMNDGmaE7OK+tg3e64DnpMHQypN4BuSS+PkVqGUoYc9f+xBMONqPscsHAGi9iU/iyZOJZKEOKOXvMmWaLoLA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@seamapi/blueprint/-/blueprint-1.6.0.tgz", + "integrity": "sha512-+lIriSgog0E0pUjXz/tdRZiVECiSiBcnZ3uU4JRN45RTLs2BQVbR+Ris6/mXwBV1wkpMetdVD3CP1BB1agf6Lg==", "dev": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 83d09c74..ef374a1a 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ } }, "devDependencies": { - "@seamapi/blueprint": "^1.5.1", + "@seamapi/blueprint": "^1.6.0", "@seamapi/fake-seam-connect": "1.86.0", "@seamapi/smith": "^1.1.0", "@seamapi/types": "1.1001.0", diff --git a/seam/resources/access_code.py b/seam/resources/access_code.py index a2e6b13a..a971deee 100644 --- a/seam/resources/access_code.py +++ b/seam/resources/access_code.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping @@ -159,14 +159,14 @@ def from_dict(cls, d: Any): created_at: Optional[str] error_code: str - is_access_code_error: Optional[bool] + is_access_code_error: Optional[Literal[True]] message: str managed_access_code_id: Optional[str] unmanaged_access_code_id: Optional[str] change_type: Optional[str] modified_fields: Optional[List[ModifiedFields]] is_connected_account_error: Optional[bool] - is_device_error: Optional[bool] + is_device_error: Optional[Literal[False, True]] is_bridge_error: Optional[bool] @classmethod @@ -345,7 +345,7 @@ def from_dict(cls, d: Any): is_backup: Optional[bool] is_backup_access_code_available: bool is_external_modification_allowed: bool - is_managed: bool + is_managed: Literal[True] is_offline_access_code: bool is_one_time_use: bool is_scheduled_on_device: Optional[bool] diff --git a/seam/resources/access_grant.py b/seam/resources/access_grant.py index 2b69e2b2..2b6c4345 100644 --- a/seam/resources/access_grant.py +++ b/seam/resources/access_grant.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/access_method.py b/seam/resources/access_method.py index fa0cf7ae..b9e83c51 100644 --- a/seam/resources/access_method.py +++ b/seam/resources/access_method.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/acs_access_group.py b/seam/resources/acs_access_group.py index 56b3a5aa..ee50739a 100644 --- a/seam/resources/acs_access_group.py +++ b/seam/resources/acs_access_group.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping @@ -223,7 +223,7 @@ def from_dict(cls, d: Any): errors: List[Errors] external_type: str external_type_display_name: str - is_managed: bool + is_managed: Literal[True] name: str pending_mutations: List[PendingMutations] warnings: List[Warnings] diff --git a/seam/resources/acs_credential.py b/seam/resources/acs_credential.py index 5d1a63c7..2baaad9f 100644 --- a/seam/resources/acs_credential.py +++ b/seam/resources/acs_credential.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping @@ -238,7 +238,7 @@ def from_dict(cls, d: Any): external_type_display_name: Optional[str] is_issued: Optional[bool] is_latest_desired_state_synced_with_provider: Optional[bool] - is_managed: bool + is_managed: Literal[True] is_multi_phone_sync_credential: Optional[bool] is_one_time_use: Optional[bool] issued_at: Optional[str] diff --git a/seam/resources/acs_encoder.py b/seam/resources/acs_encoder.py index 6a8db9db..e1f52f93 100644 --- a/seam/resources/acs_encoder.py +++ b/seam/resources/acs_encoder.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/acs_entrance.py b/seam/resources/acs_entrance.py index 6e7ac32b..148c3ba6 100644 --- a/seam/resources/acs_entrance.py +++ b/seam/resources/acs_entrance.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/acs_system.py b/seam/resources/acs_system.py index e3f80f8e..0ae9b83f 100644 --- a/seam/resources/acs_system.py +++ b/seam/resources/acs_system.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/acs_user.py b/seam/resources/acs_user.py index 91a27457..4c1ffe44 100644 --- a/seam/resources/acs_user.py +++ b/seam/resources/acs_user.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping @@ -304,7 +304,7 @@ def from_dict(cls, d: Any): external_type_display_name: Optional[str] full_name: Optional[str] hid_acs_system_id: Optional[str] - is_managed: bool + is_managed: Literal[True] is_suspended: Optional[bool] pending_mutations: Optional[List[PendingMutations]] phone_number: Optional[str] diff --git a/seam/resources/action_attempt.py b/seam/resources/action_attempt.py index 9237bbc9..852d5e02 100644 --- a/seam/resources/action_attempt.py +++ b/seam/resources/action_attempt.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping @@ -456,7 +456,7 @@ def from_dict(cls, d: Any): external_type_display_name: Optional[str] is_issued: Optional[bool] is_latest_desired_state_synced_with_provider: Optional[bool] - is_managed: bool + is_managed: Literal[True, False] is_multi_phone_sync_credential: Optional[bool] is_one_time_use: Optional[bool] issued_at: Optional[str] @@ -778,7 +778,7 @@ def from_dict(cls, d: Any): external_type_display_name: Optional[str] is_issued: Optional[bool] is_latest_desired_state_synced_with_provider: Optional[bool] - is_managed: Optional[bool] + is_managed: Optional[Literal[True, False]] is_multi_phone_sync_credential: Optional[bool] is_one_time_use: Optional[bool] issued_at: Optional[str] diff --git a/seam/resources/batch.py b/seam/resources/batch.py index 2020ea25..cdd4151b 100644 --- a/seam/resources/batch.py +++ b/seam/resources/batch.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/client_session.py b/seam/resources/client_session.py index 09bc23cd..0c79303d 100644 --- a/seam/resources/client_session.py +++ b/seam/resources/client_session.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/connect_webview.py b/seam/resources/connect_webview.py index a5e8ae83..36d29103 100644 --- a/seam/resources/connect_webview.py +++ b/seam/resources/connect_webview.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/connected_account.py b/seam/resources/connected_account.py index 3acefeb6..d027b8fe 100644 --- a/seam/resources/connected_account.py +++ b/seam/resources/connected_account.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/customer_portal.py b/seam/resources/customer_portal.py index e3c0d10c..8610ef79 100644 --- a/seam/resources/customer_portal.py +++ b/seam/resources/customer_portal.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/device.py b/seam/resources/device.py index 694db4c6..5946700f 100644 --- a/seam/resources/device.py +++ b/seam/resources/device.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping @@ -153,7 +153,7 @@ class Errors(ResourceMapping): created_at: str error_code: str is_connected_account_error: Optional[bool] - is_device_error: Optional[bool] + is_device_error: Optional[Literal[False, True]] message: str is_bridge_error: Optional[bool] @@ -2106,7 +2106,7 @@ def from_dict(cls, d: Any): display_name: str end_date_recurrence_rule: Optional[str] - matching_start_end_time: Optional[bool] + matching_start_end_time: Optional[Literal[True]] max_duration: Optional[str] min_duration: Optional[str] start_date_recurrence_rule: Optional[str] @@ -2176,7 +2176,7 @@ def from_dict(cls, d: Any): display_name: str end_date_recurrence_rule: Optional[str] - matching_start_end_time: Optional[bool] + matching_start_end_time: Optional[Literal[True]] max_duration: Optional[str] min_duration: Optional[str] start_date_recurrence_rule: Optional[str] @@ -3282,7 +3282,7 @@ def from_dict(cls, d: Any): device_type: str display_name: str errors: List[Errors] - is_managed: bool + is_managed: Literal[True] location: Optional[Location] nickname: Optional[str] properties: Optional[Properties] diff --git a/seam/resources/device_provider.py b/seam/resources/device_provider.py index 2f78b766..5d525cdb 100644 --- a/seam/resources/device_provider.py +++ b/seam/resources/device_provider.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/instant_key.py b/seam/resources/instant_key.py index e31f062c..66a6c74a 100644 --- a/seam/resources/instant_key.py +++ b/seam/resources/instant_key.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/noise_threshold.py b/seam/resources/noise_threshold.py index f87091c1..5ffb202c 100644 --- a/seam/resources/noise_threshold.py +++ b/seam/resources/noise_threshold.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/pagination.py b/seam/resources/pagination.py index 8a265084..13798329 100644 --- a/seam/resources/pagination.py +++ b/seam/resources/pagination.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/phone.py b/seam/resources/phone.py index 2b7554bb..67cfbb39 100644 --- a/seam/resources/phone.py +++ b/seam/resources/phone.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/seam_event.py b/seam/resources/seam_event.py index 62fdd2ac..0d089e8d 100644 --- a/seam/resources/seam_event.py +++ b/seam/resources/seam_event.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/space.py b/seam/resources/space.py index 3c7ece26..5bb3ec7a 100644 --- a/seam/resources/space.py +++ b/seam/resources/space.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/thermostat_daily_program.py b/seam/resources/thermostat_daily_program.py index fe25f674..9fbcc162 100644 --- a/seam/resources/thermostat_daily_program.py +++ b/seam/resources/thermostat_daily_program.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/thermostat_schedule.py b/seam/resources/thermostat_schedule.py index 2fd44b48..acd574a0 100644 --- a/seam/resources/thermostat_schedule.py +++ b/seam/resources/thermostat_schedule.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/unmanaged_access_code.py b/seam/resources/unmanaged_access_code.py index 056f6105..a2e7676c 100644 --- a/seam/resources/unmanaged_access_code.py +++ b/seam/resources/unmanaged_access_code.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping @@ -145,14 +145,14 @@ def from_dict(cls, d: Any): created_at: Optional[str] error_code: str - is_access_code_error: Optional[bool] + is_access_code_error: Optional[Literal[True]] message: str managed_access_code_id: Optional[str] unmanaged_access_code_id: Optional[str] change_type: Optional[str] modified_fields: Optional[List[ModifiedFields]] is_connected_account_error: Optional[bool] - is_device_error: Optional[bool] + is_device_error: Optional[Literal[False, True]] is_bridge_error: Optional[bool] @classmethod @@ -231,15 +231,15 @@ def from_dict(cls, d: Any): ) access_code_id: str - cannot_be_managed: Optional[bool] - cannot_delete_unmanaged_access_code: Optional[bool] + cannot_be_managed: Optional[Literal[True]] + cannot_delete_unmanaged_access_code: Optional[Literal[True]] code: Optional[str] created_at: str device_id: str dormakaba_oracode_metadata: Optional[DormakabaOracodeMetadata] ends_at: Optional[str] errors: List[Errors] - is_managed: bool + is_managed: Literal[False] name: Optional[str] starts_at: Optional[str] status: str diff --git a/seam/resources/unmanaged_access_grant.py b/seam/resources/unmanaged_access_grant.py index 4507a66a..9fc48ad4 100644 --- a/seam/resources/unmanaged_access_grant.py +++ b/seam/resources/unmanaged_access_grant.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/unmanaged_access_method.py b/seam/resources/unmanaged_access_method.py index c789d61e..32b3a56e 100644 --- a/seam/resources/unmanaged_access_method.py +++ b/seam/resources/unmanaged_access_method.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/unmanaged_device.py b/seam/resources/unmanaged_device.py index fddb1589..6b42932b 100644 --- a/seam/resources/unmanaged_device.py +++ b/seam/resources/unmanaged_device.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping @@ -93,7 +93,7 @@ class Errors(ResourceMapping): created_at: str error_code: str is_connected_account_error: Optional[bool] - is_device_error: Optional[bool] + is_device_error: Optional[Literal[False, True]] message: str is_bridge_error: Optional[bool] @@ -367,7 +367,7 @@ def from_dict(cls, d: Any): device_id: str device_type: str errors: List[Errors] - is_managed: bool + is_managed: Literal[False] location: Optional[Location] properties: Optional[Properties] warnings: List[Warnings] diff --git a/seam/resources/unmanaged_user_identity.py b/seam/resources/unmanaged_user_identity.py index 41dd2af5..657c526c 100644 --- a/seam/resources/unmanaged_user_identity.py +++ b/seam/resources/unmanaged_user_identity.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/user_identity.py b/seam/resources/user_identity.py index 19e7d548..8cf8e309 100644 --- a/seam/resources/user_identity.py +++ b/seam/resources/user_identity.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/webhook.py b/seam/resources/webhook.py index 86cea9de..663accd2 100644 --- a/seam/resources/webhook.py +++ b/seam/resources/webhook.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/resources/workspace.py b/seam/resources/workspace.py index 3b926d45..dc97140d 100644 --- a/seam/resources/workspace.py +++ b/seam/resources/workspace.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List, Optional, Union +from typing import Any, Dict, List, Literal, Optional, Union from dataclasses import dataclass from ..deep_attr_dict import DeepAttrDict from ..resource_mapping import ResourceMapping diff --git a/seam/routes/access_codes.py b/seam/routes/access_codes.py index 3f5053f5..8ad4923d 100644 --- a/seam/routes/access_codes.py +++ b/seam/routes/access_codes.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/access_codes_simulate.py b/seam/routes/access_codes_simulate.py index 4c4c756c..1faed843 100644 --- a/seam/routes/access_codes_simulate.py +++ b/seam/routes/access_codes_simulate.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/access_codes_unmanaged.py b/seam/routes/access_codes_unmanaged.py index 8a6e67d4..0f53f032 100644 --- a/seam/routes/access_codes_unmanaged.py +++ b/seam/routes/access_codes_unmanaged.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/access_grants.py b/seam/routes/access_grants.py index fbc7685a..8b396e95 100644 --- a/seam/routes/access_grants.py +++ b/seam/routes/access_grants.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/access_grants_unmanaged.py b/seam/routes/access_grants_unmanaged.py index 843709e8..95f338d2 100644 --- a/seam/routes/access_grants_unmanaged.py +++ b/seam/routes/access_grants_unmanaged.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata @@ -52,7 +52,7 @@ def update( self, *, access_grant_id: str, - is_managed: bool, + is_managed: Literal[True], access_grant_key: Optional[str] = None, ) -> None: """Updates an unmanaged Access Grant to make it managed. @@ -161,7 +161,7 @@ def update( self, *, access_grant_id: str, - is_managed: bool, + is_managed: Literal[True], access_grant_key: Optional[str] = None, ) -> None: """Updates an unmanaged Access Grant to make it managed. diff --git a/seam/routes/access_methods.py b/seam/routes/access_methods.py index 915c4773..c98b1296 100644 --- a/seam/routes/access_methods.py +++ b/seam/routes/access_methods.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/access_methods_unmanaged.py b/seam/routes/access_methods_unmanaged.py index fd7cd14a..e0c4b591 100644 --- a/seam/routes/access_methods_unmanaged.py +++ b/seam/routes/access_methods_unmanaged.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/acs.py b/seam/routes/acs.py index 125f3c31..32e8a724 100644 --- a/seam/routes/acs.py +++ b/seam/routes/acs.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/acs_access_groups.py b/seam/routes/acs_access_groups.py index 6b84487e..c4557563 100644 --- a/seam/routes/acs_access_groups.py +++ b/seam/routes/acs_access_groups.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/acs_credentials.py b/seam/routes/acs_credentials.py index ceff9409..c3be5f9a 100644 --- a/seam/routes/acs_credentials.py +++ b/seam/routes/acs_credentials.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/acs_encoders.py b/seam/routes/acs_encoders.py index 5b6d9c8a..e90f2b5f 100644 --- a/seam/routes/acs_encoders.py +++ b/seam/routes/acs_encoders.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/acs_encoders_simulate.py b/seam/routes/acs_encoders_simulate.py index ac0d1793..d5819adc 100644 --- a/seam/routes/acs_encoders_simulate.py +++ b/seam/routes/acs_encoders_simulate.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/acs_entrances.py b/seam/routes/acs_entrances.py index ddb863d4..8973de38 100644 --- a/seam/routes/acs_entrances.py +++ b/seam/routes/acs_entrances.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/acs_systems.py b/seam/routes/acs_systems.py index 7eb41612..0766d017 100644 --- a/seam/routes/acs_systems.py +++ b/seam/routes/acs_systems.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/acs_users.py b/seam/routes/acs_users.py index 1da621eb..72d854e8 100644 --- a/seam/routes/acs_users.py +++ b/seam/routes/acs_users.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/action_attempts.py b/seam/routes/action_attempts.py index 8f0c221c..dc1a1470 100644 --- a/seam/routes/action_attempts.py +++ b/seam/routes/action_attempts.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/client_sessions.py b/seam/routes/client_sessions.py index 62da3156..50414c6a 100644 --- a/seam/routes/client_sessions.py +++ b/seam/routes/client_sessions.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/connect_webviews.py b/seam/routes/connect_webviews.py index 053ed685..45300e07 100644 --- a/seam/routes/connect_webviews.py +++ b/seam/routes/connect_webviews.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/connected_accounts.py b/seam/routes/connected_accounts.py index 7c50bfd2..a803c0f0 100644 --- a/seam/routes/connected_accounts.py +++ b/seam/routes/connected_accounts.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/connected_accounts_simulate.py b/seam/routes/connected_accounts_simulate.py index 76df8f62..3837200f 100644 --- a/seam/routes/connected_accounts_simulate.py +++ b/seam/routes/connected_accounts_simulate.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/customers.py b/seam/routes/customers.py index 494848c5..6130f955 100644 --- a/seam/routes/customers.py +++ b/seam/routes/customers.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/devices.py b/seam/routes/devices.py index e1b6dfbb..ff88d253 100644 --- a/seam/routes/devices.py +++ b/seam/routes/devices.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/devices_simulate.py b/seam/routes/devices_simulate.py index dfdfdfed..f76b5d83 100644 --- a/seam/routes/devices_simulate.py +++ b/seam/routes/devices_simulate.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/devices_unmanaged.py b/seam/routes/devices_unmanaged.py index 12987d60..37fd90ed 100644 --- a/seam/routes/devices_unmanaged.py +++ b/seam/routes/devices_unmanaged.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata @@ -81,7 +81,7 @@ def update( *, device_id: str, custom_metadata: Optional[Dict[str, Any]] = None, - is_managed: Optional[bool] = None, + is_managed: Optional[Literal[True]] = None, ) -> None: """Updates a specified `unmanaged device `_. To convert an unmanaged device to managed, set ``is_managed`` to ``true``. @@ -230,7 +230,7 @@ def update( *, device_id: str, custom_metadata: Optional[Dict[str, Any]] = None, - is_managed: Optional[bool] = None, + is_managed: Optional[Literal[True]] = None, ) -> None: """Updates a specified `unmanaged device `_. To convert an unmanaged device to managed, set ``is_managed`` to ``true``. diff --git a/seam/routes/events.py b/seam/routes/events.py index 8613b639..24cf174e 100644 --- a/seam/routes/events.py +++ b/seam/routes/events.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/instant_keys.py b/seam/routes/instant_keys.py index 48787987..eb3e1a07 100644 --- a/seam/routes/instant_keys.py +++ b/seam/routes/instant_keys.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/locks.py b/seam/routes/locks.py index fdf7843f..2165d268 100644 --- a/seam/routes/locks.py +++ b/seam/routes/locks.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/locks_simulate.py b/seam/routes/locks_simulate.py index 6979c9c2..b91c579f 100644 --- a/seam/routes/locks_simulate.py +++ b/seam/routes/locks_simulate.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/noise_sensors.py b/seam/routes/noise_sensors.py index 6ab4492b..d93c1c78 100644 --- a/seam/routes/noise_sensors.py +++ b/seam/routes/noise_sensors.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/noise_sensors_noise_thresholds.py b/seam/routes/noise_sensors_noise_thresholds.py index 54c90ce8..bc4277b7 100644 --- a/seam/routes/noise_sensors_noise_thresholds.py +++ b/seam/routes/noise_sensors_noise_thresholds.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/noise_sensors_simulate.py b/seam/routes/noise_sensors_simulate.py index 6c527582..5f02cb8d 100644 --- a/seam/routes/noise_sensors_simulate.py +++ b/seam/routes/noise_sensors_simulate.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/phones.py b/seam/routes/phones.py index a00d49f4..c02fa99b 100644 --- a/seam/routes/phones.py +++ b/seam/routes/phones.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/phones_simulate.py b/seam/routes/phones_simulate.py index 58b47aca..debcd589 100644 --- a/seam/routes/phones_simulate.py +++ b/seam/routes/phones_simulate.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/spaces.py b/seam/routes/spaces.py index 56f80f37..17b8175f 100644 --- a/seam/routes/spaces.py +++ b/seam/routes/spaces.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/thermostats.py b/seam/routes/thermostats.py index 231090d3..92737404 100644 --- a/seam/routes/thermostats.py +++ b/seam/routes/thermostats.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/thermostats_daily_programs.py b/seam/routes/thermostats_daily_programs.py index cff60944..24738cc2 100644 --- a/seam/routes/thermostats_daily_programs.py +++ b/seam/routes/thermostats_daily_programs.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/thermostats_schedules.py b/seam/routes/thermostats_schedules.py index 7c4787ad..ffb37f5d 100644 --- a/seam/routes/thermostats_schedules.py +++ b/seam/routes/thermostats_schedules.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/thermostats_simulate.py b/seam/routes/thermostats_simulate.py index 69dec843..992d7663 100644 --- a/seam/routes/thermostats_simulate.py +++ b/seam/routes/thermostats_simulate.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/user_identities.py b/seam/routes/user_identities.py index a9107bc6..9f3c1fba 100644 --- a/seam/routes/user_identities.py +++ b/seam/routes/user_identities.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/user_identities_unmanaged.py b/seam/routes/user_identities_unmanaged.py index b177177a..456a3e51 100644 --- a/seam/routes/user_identities_unmanaged.py +++ b/seam/routes/user_identities_unmanaged.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata @@ -45,7 +45,7 @@ def list( def update( self, *, - is_managed: bool, + is_managed: Literal[True], user_identity_id: str, user_identity_key: Optional[str] = None, ) -> None: @@ -144,7 +144,7 @@ def list( def update( self, *, - is_managed: bool, + is_managed: Literal[True], user_identity_id: str, user_identity_key: Optional[str] = None, ) -> None: diff --git a/seam/routes/webhooks.py b/seam/routes/webhooks.py index 8aa22a82..736b1040 100644 --- a/seam/routes/webhooks.py +++ b/seam/routes/webhooks.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/seam/routes/workspaces.py b/seam/routes/workspaces.py index 01ee6655..bcfb26d6 100644 --- a/seam/routes/workspaces.py +++ b/seam/routes/workspaces.py @@ -1,4 +1,4 @@ -from typing import Optional, Any, List, Dict, Union +from typing import Optional, Any, List, Dict, Literal, Union import abc from ..client import SeamHttpClient from ..route import route_metadata diff --git a/test/resource_types_test.py b/test/resource_types_test.py new file mode 100644 index 00000000..6646e459 --- /dev/null +++ b/test/resource_types_test.py @@ -0,0 +1,35 @@ +# mypy: warn_unused_ignores=True + +from typing import Literal, assert_type + +from seam.resources import AccessCode, ActionAttempt, UnmanagedAccessCode + + +def _assert_access_code_narrowing( + code: AccessCode | UnmanagedAccessCode, +) -> None: + if code.is_managed: + assert_type(code, AccessCode) + else: + assert_type(code, UnmanagedAccessCode) + + +def _assert_boolean_shapes( + code: AccessCode, + unmanaged_code: UnmanagedAccessCode, + credential: ActionAttempt.Result.AcsCredentialOnSeam, +) -> None: + assert_type(code.is_backup_access_code_available, bool) + assert_type(code.errors[0].is_access_code_error, Literal[True] | None) + assert_type(unmanaged_code.errors[0].is_connected_account_error, bool | None) + assert_type(credential.is_managed, Literal[True, False]) + + +def _assert_opposite_literal_is_rejected(code: UnmanagedAccessCode) -> None: + code.is_managed = True # type: ignore[assignment] + + +def test_access_code_resources_narrow_on_is_managed(): + assert callable(_assert_access_code_narrowing) + assert callable(_assert_boolean_shapes) + assert callable(_assert_opposite_literal_is_rejected)