mergepythonclient 0.0.1__py3-none-any.whl
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.
- merge/__init__.py +77 -0
- merge/_base_client.py +1431 -0
- merge/_base_exceptions.py +117 -0
- merge/_client.py +344 -0
- merge/_exceptions.py +31 -0
- merge/_models.py +235 -0
- merge/_qs.py +148 -0
- merge/_resource.py +34 -0
- merge/_types.py +145 -0
- merge/_utils/__init__.py +25 -0
- merge/_utils/_transform.py +205 -0
- merge/_utils/_utils.py +325 -0
- merge/_version.py +4 -0
- merge/pagination.py +43 -0
- merge/py.typed +0 -0
- merge/resources/__init__.py +26 -0
- merge/resources/accounting/__init__.py +104 -0
- merge/resources/accounting/account_details.py +52 -0
- merge/resources/accounting/account_tokens.py +54 -0
- merge/resources/accounting/accounting.py +184 -0
- merge/resources/accounting/accounts/__init__.py +6 -0
- merge/resources/accounting/accounts/accounts.py +428 -0
- merge/resources/accounting/accounts/meta.py +52 -0
- merge/resources/accounting/addresses.py +122 -0
- merge/resources/accounting/attachments/__init__.py +6 -0
- merge/resources/accounting/attachments/attachments.py +371 -0
- merge/resources/accounting/attachments/meta.py +52 -0
- merge/resources/accounting/available_actions.py +52 -0
- merge/resources/accounting/balance_sheets.py +294 -0
- merge/resources/accounting/cash_flow_statements.py +294 -0
- merge/resources/accounting/common_model_scopes.py +185 -0
- merge/resources/accounting/company_info.py +286 -0
- merge/resources/accounting/contacts/__init__.py +6 -0
- merge/resources/accounting/contacts/contacts.py +428 -0
- merge/resources/accounting/contacts/meta.py +52 -0
- merge/resources/accounting/credit_notes.py +342 -0
- merge/resources/accounting/expenses/__init__.py +6 -0
- merge/resources/accounting/expenses/expenses.py +416 -0
- merge/resources/accounting/expenses/meta.py +52 -0
- merge/resources/accounting/income_statements.py +294 -0
- merge/resources/accounting/invoices/__init__.py +6 -0
- merge/resources/accounting/invoices/invoices.py +472 -0
- merge/resources/accounting/invoices/meta.py +52 -0
- merge/resources/accounting/issues.py +251 -0
- merge/resources/accounting/items.py +322 -0
- merge/resources/accounting/journal_entries/__init__.py +6 -0
- merge/resources/accounting/journal_entries/journal_entries.py +416 -0
- merge/resources/accounting/journal_entries/meta.py +52 -0
- merge/resources/accounting/link_tokens.py +173 -0
- merge/resources/accounting/linked_accounts.py +286 -0
- merge/resources/accounting/passthrough_requests.py +167 -0
- merge/resources/accounting/payments/__init__.py +6 -0
- merge/resources/accounting/payments/meta.py +52 -0
- merge/resources/accounting/payments/payments.py +430 -0
- merge/resources/accounting/phone_numbers.py +97 -0
- merge/resources/accounting/purchase_orders/__init__.py +6 -0
- merge/resources/accounting/purchase_orders/meta.py +52 -0
- merge/resources/accounting/purchase_orders/purchase_orders.py +452 -0
- merge/resources/accounting/remote_keys.py +144 -0
- merge/resources/accounting/selective_sync.py +234 -0
- merge/resources/accounting/sync_status.py +167 -0
- merge/resources/accounting/tax_rates.py +290 -0
- merge/resources/accounting/tracking_categories.py +326 -0
- merge/resources/accounting/transactions.py +310 -0
- merge/resources/accounting/vendor_credits.py +310 -0
- merge/resources/accounting/webhook_receivers.py +139 -0
- merge/resources/ats/__init__.py +89 -0
- merge/resources/ats/account_details.py +52 -0
- merge/resources/ats/account_tokens.py +54 -0
- merge/resources/ats/activities/__init__.py +6 -0
- merge/resources/ats/activities/activities.py +446 -0
- merge/resources/ats/activities/meta.py +52 -0
- merge/resources/ats/applications/__init__.py +6 -0
- merge/resources/ats/applications/applications.py +547 -0
- merge/resources/ats/applications/meta.py +96 -0
- merge/resources/ats/ats.py +159 -0
- merge/resources/ats/attachments/__init__.py +6 -0
- merge/resources/ats/attachments/attachments.py +442 -0
- merge/resources/ats/attachments/meta.py +52 -0
- merge/resources/ats/available_actions.py +52 -0
- merge/resources/ats/candidates/__init__.py +6 -0
- merge/resources/ats/candidates/candidates.py +543 -0
- merge/resources/ats/candidates/meta.py +52 -0
- merge/resources/ats/common_model_scopes.py +185 -0
- merge/resources/ats/departments.py +255 -0
- merge/resources/ats/eeocs.py +458 -0
- merge/resources/ats/interviews/__init__.py +6 -0
- merge/resources/ats/interviews/interviews.py +464 -0
- merge/resources/ats/interviews/meta.py +52 -0
- merge/resources/ats/issues.py +251 -0
- merge/resources/ats/job_interview_stages.py +294 -0
- merge/resources/ats/jobs.py +354 -0
- merge/resources/ats/link_tokens.py +173 -0
- merge/resources/ats/linked_accounts.py +286 -0
- merge/resources/ats/offers.py +330 -0
- merge/resources/ats/offices.py +255 -0
- merge/resources/ats/passthrough_requests.py +167 -0
- merge/resources/ats/reject_reasons.py +261 -0
- merge/resources/ats/remote_keys.py +144 -0
- merge/resources/ats/scorecards.py +338 -0
- merge/resources/ats/selective_sync.py +234 -0
- merge/resources/ats/sync_status.py +167 -0
- merge/resources/ats/tags.py +174 -0
- merge/resources/ats/users.py +303 -0
- merge/resources/ats/webhook_receivers.py +136 -0
- merge/resources/crm/__init__.py +80 -0
- merge/resources/crm/account_details.py +52 -0
- merge/resources/crm/account_tokens.py +54 -0
- merge/resources/crm/accounts/__init__.py +6 -0
- merge/resources/crm/accounts/accounts.py +626 -0
- merge/resources/crm/accounts/meta.py +92 -0
- merge/resources/crm/available_actions.py +52 -0
- merge/resources/crm/common_model_scopes.py +185 -0
- merge/resources/crm/contacts/__init__.py +6 -0
- merge/resources/crm/contacts/contacts.py +727 -0
- merge/resources/crm/contacts/meta.py +92 -0
- merge/resources/crm/crm.py +144 -0
- merge/resources/crm/custom_object_classes/__init__.py +6 -0
- merge/resources/crm/custom_object_classes/association_types/__init__.py +6 -0
- merge/resources/crm/custom_object_classes/association_types/association_types.py +374 -0
- merge/resources/crm/custom_object_classes/association_types/meta.py +54 -0
- merge/resources/crm/custom_object_classes/custom_object_classes.py +302 -0
- merge/resources/crm/custom_objects/__init__.py +17 -0
- merge/resources/crm/custom_objects/associations.py +250 -0
- merge/resources/crm/custom_objects/custom_objects.py +452 -0
- merge/resources/crm/custom_objects/generators.py +54 -0
- merge/resources/crm/custom_objects/meta.py +96 -0
- merge/resources/crm/engagement_types.py +409 -0
- merge/resources/crm/engagements/__init__.py +6 -0
- merge/resources/crm/engagements/engagements.py +623 -0
- merge/resources/crm/engagements/meta.py +92 -0
- merge/resources/crm/issues.py +251 -0
- merge/resources/crm/leads/__init__.py +6 -0
- merge/resources/crm/leads/leads.py +558 -0
- merge/resources/crm/leads/meta.py +52 -0
- merge/resources/crm/link_tokens.py +173 -0
- merge/resources/crm/linked_accounts.py +286 -0
- merge/resources/crm/notes/__init__.py +6 -0
- merge/resources/crm/notes/meta.py +52 -0
- merge/resources/crm/notes/notes.py +564 -0
- merge/resources/crm/opportunities/__init__.py +6 -0
- merge/resources/crm/opportunities/meta.py +92 -0
- merge/resources/crm/opportunities/opportunities.py +697 -0
- merge/resources/crm/passthrough_requests.py +167 -0
- merge/resources/crm/remote_keys.py +144 -0
- merge/resources/crm/selective_sync.py +234 -0
- merge/resources/crm/stages.py +409 -0
- merge/resources/crm/sync_status.py +167 -0
- merge/resources/crm/tasks/__init__.py +6 -0
- merge/resources/crm/tasks/meta.py +92 -0
- merge/resources/crm/tasks/tasks.py +619 -0
- merge/resources/crm/users.py +509 -0
- merge/resources/crm/webhook_receivers.py +136 -0
- merge/resources/file_storage/__init__.py +59 -0
- merge/resources/file_storage/account_details.py +52 -0
- merge/resources/file_storage/account_tokens.py +54 -0
- merge/resources/file_storage/available_actions.py +52 -0
- merge/resources/file_storage/common_model_scopes.py +185 -0
- merge/resources/file_storage/drives.py +265 -0
- merge/resources/file_storage/file_storage.py +109 -0
- merge/resources/file_storage/files/__init__.py +6 -0
- merge/resources/file_storage/files/files.py +452 -0
- merge/resources/file_storage/files/meta.py +52 -0
- merge/resources/file_storage/folders/__init__.py +6 -0
- merge/resources/file_storage/folders/folders.py +420 -0
- merge/resources/file_storage/folders/meta.py +52 -0
- merge/resources/file_storage/groups.py +255 -0
- merge/resources/file_storage/issues.py +251 -0
- merge/resources/file_storage/link_tokens.py +173 -0
- merge/resources/file_storage/linked_accounts.py +286 -0
- merge/resources/file_storage/passthrough_requests.py +167 -0
- merge/resources/file_storage/remote_keys.py +147 -0
- merge/resources/file_storage/selective_sync.py +234 -0
- merge/resources/file_storage/sync_status.py +167 -0
- merge/resources/file_storage/users.py +255 -0
- merge/resources/file_storage/webhook_receivers.py +139 -0
- merge/resources/hris/__init__.py +83 -0
- merge/resources/hris/account_details.py +52 -0
- merge/resources/hris/account_tokens.py +54 -0
- merge/resources/hris/available_actions.py +52 -0
- merge/resources/hris/banks.py +356 -0
- merge/resources/hris/benefits.py +290 -0
- merge/resources/hris/common_model_scopes.py +185 -0
- merge/resources/hris/companies.py +255 -0
- merge/resources/hris/employee_payroll_runs.py +336 -0
- merge/resources/hris/employees/__init__.py +6 -0
- merge/resources/hris/employees/employees.py +841 -0
- merge/resources/hris/employees/meta.py +52 -0
- merge/resources/hris/employments.py +466 -0
- merge/resources/hris/groups.py +304 -0
- merge/resources/hris/hris.py +149 -0
- merge/resources/hris/issues.py +251 -0
- merge/resources/hris/link_tokens.py +173 -0
- merge/resources/hris/linked_accounts.py +286 -0
- merge/resources/hris/locations.py +294 -0
- merge/resources/hris/passthrough_requests.py +167 -0
- merge/resources/hris/pay_groups.py +255 -0
- merge/resources/hris/payroll_runs.py +356 -0
- merge/resources/hris/remote_keys.py +144 -0
- merge/resources/hris/selective_sync.py +234 -0
- merge/resources/hris/sync_status.py +167 -0
- merge/resources/hris/teams.py +291 -0
- merge/resources/hris/time_off/__init__.py +6 -0
- merge/resources/hris/time_off/meta.py +52 -0
- merge/resources/hris/time_off/time_off.py +560 -0
- merge/resources/hris/time_off_balances.py +354 -0
- merge/resources/hris/webhook_receivers.py +136 -0
- merge/resources/marketing/__init__.py +74 -0
- merge/resources/marketing/account_details.py +52 -0
- merge/resources/marketing/account_tokens.py +54 -0
- merge/resources/marketing/actions/__init__.py +6 -0
- merge/resources/marketing/actions/actions.py +363 -0
- merge/resources/marketing/actions/meta.py +52 -0
- merge/resources/marketing/automations/__init__.py +6 -0
- merge/resources/marketing/automations/automations.py +481 -0
- merge/resources/marketing/automations/meta.py +52 -0
- merge/resources/marketing/available_actions.py +52 -0
- merge/resources/marketing/campaigns/__init__.py +6 -0
- merge/resources/marketing/campaigns/campaigns.py +481 -0
- merge/resources/marketing/campaigns/meta.py +52 -0
- merge/resources/marketing/common_model_scopes.py +185 -0
- merge/resources/marketing/contact_lists/__init__.py +6 -0
- merge/resources/marketing/contact_lists/contact_lists.py +477 -0
- merge/resources/marketing/contact_lists/meta.py +52 -0
- merge/resources/marketing/contacts/__init__.py +6 -0
- merge/resources/marketing/contacts/contacts.py +361 -0
- merge/resources/marketing/contacts/meta.py +52 -0
- merge/resources/marketing/emails.py +375 -0
- merge/resources/marketing/events.py +375 -0
- merge/resources/marketing/issues.py +251 -0
- merge/resources/marketing/link_tokens.py +173 -0
- merge/resources/marketing/linked_accounts.py +286 -0
- merge/resources/marketing/marketing.py +134 -0
- merge/resources/marketing/messages.py +375 -0
- merge/resources/marketing/passthrough_requests.py +167 -0
- merge/resources/marketing/remote_keys.py +144 -0
- merge/resources/marketing/selective_sync.py +234 -0
- merge/resources/marketing/sync_status.py +167 -0
- merge/resources/marketing/templates/__init__.py +6 -0
- merge/resources/marketing/templates/meta.py +52 -0
- merge/resources/marketing/templates/templates.py +365 -0
- merge/resources/marketing/users.py +255 -0
- merge/resources/marketing/webhook_receivers.py +139 -0
- merge/resources/ticketing/__init__.py +74 -0
- merge/resources/ticketing/account_details.py +52 -0
- merge/resources/ticketing/account_tokens.py +54 -0
- merge/resources/ticketing/accounts.py +256 -0
- merge/resources/ticketing/attachments/__init__.py +6 -0
- merge/resources/ticketing/attachments/attachments.py +396 -0
- merge/resources/ticketing/attachments/meta.py +52 -0
- merge/resources/ticketing/available_actions.py +52 -0
- merge/resources/ticketing/collections.py +468 -0
- merge/resources/ticketing/comments/__init__.py +6 -0
- merge/resources/ticketing/comments/comments.py +396 -0
- merge/resources/ticketing/comments/meta.py +52 -0
- merge/resources/ticketing/common_model_scopes.py +185 -0
- merge/resources/ticketing/contacts.py +283 -0
- merge/resources/ticketing/issues.py +251 -0
- merge/resources/ticketing/link_tokens.py +173 -0
- merge/resources/ticketing/linked_accounts.py +286 -0
- merge/resources/ticketing/passthrough_requests.py +167 -0
- merge/resources/ticketing/projects.py +386 -0
- merge/resources/ticketing/remote_keys.py +144 -0
- merge/resources/ticketing/selective_sync.py +234 -0
- merge/resources/ticketing/sync_status.py +167 -0
- merge/resources/ticketing/tags.py +256 -0
- merge/resources/ticketing/teams.py +256 -0
- merge/resources/ticketing/ticketing.py +134 -0
- merge/resources/ticketing/tickets/__init__.py +6 -0
- merge/resources/ticketing/tickets/meta.py +92 -0
- merge/resources/ticketing/tickets/tickets.py +1037 -0
- merge/resources/ticketing/users.py +292 -0
- merge/resources/ticketing/webhook_receivers.py +139 -0
- merge/types/__init__.py +33 -0
- merge/types/accounting/__init__.py +155 -0
- merge/types/accounting/account_create_params.py +706 -0
- merge/types/accounting/account_list_params.py +63 -0
- merge/types/accounting/account_response.py +28 -0
- merge/types/accounting/account_retrieve_params.py +28 -0
- merge/types/accounting/accounting_attachment.py +35 -0
- merge/types/accounting/accounting_attachment_response.py +30 -0
- merge/types/accounting/accounts/__init__.py +3 -0
- merge/types/accounting/address_retrieve_params.py +21 -0
- merge/types/accounting/attachment_create_params.py +38 -0
- merge/types/accounting/attachment_list_params.py +51 -0
- merge/types/accounting/attachment_retrieve_params.py +15 -0
- merge/types/accounting/attachments/__init__.py +3 -0
- merge/types/accounting/balance_sheet.py +728 -0
- merge/types/accounting/balance_sheet_list_params.py +57 -0
- merge/types/accounting/balance_sheet_retrieve_params.py +22 -0
- merge/types/accounting/cash_flow_statement.py +730 -0
- merge/types/accounting/cash_flow_statement_list_params.py +57 -0
- merge/types/accounting/cash_flow_statement_retrieve_params.py +22 -0
- merge/types/accounting/common_model_scope_retrieve_params.py +12 -0
- merge/types/accounting/common_model_scope_update_params.py +21 -0
- merge/types/accounting/company_info.py +672 -0
- merge/types/accounting/company_info_list_params.py +54 -0
- merge/types/accounting/company_info_retrieve_params.py +22 -0
- merge/types/accounting/contact_create_params.py +384 -0
- merge/types/accounting/contact_list_params.py +63 -0
- merge/types/accounting/contact_response.py +28 -0
- merge/types/accounting/contact_retrieve_params.py +28 -0
- merge/types/accounting/contacts/__init__.py +3 -0
- merge/types/accounting/credit_note.py +727 -0
- merge/types/accounting/credit_note_list_params.py +69 -0
- merge/types/accounting/credit_note_retrieve_params.py +28 -0
- merge/types/accounting/expense.py +707 -0
- merge/types/accounting/expense_create_params.py +709 -0
- merge/types/accounting/expense_list_params.py +63 -0
- merge/types/accounting/expense_response.py +31 -0
- merge/types/accounting/expense_retrieve_params.py +22 -0
- merge/types/accounting/expenses/__init__.py +3 -0
- merge/types/accounting/income_statement.py +751 -0
- merge/types/accounting/income_statement_list_params.py +57 -0
- merge/types/accounting/income_statement_retrieve_params.py +22 -0
- merge/types/accounting/invoice.py +1357 -0
- merge/types/accounting/invoice_create_params.py +1351 -0
- merge/types/accounting/invoice_list_params.py +79 -0
- merge/types/accounting/invoice_response.py +30 -0
- merge/types/accounting/invoice_retrieve_params.py +28 -0
- merge/types/accounting/invoices/__init__.py +3 -0
- merge/types/accounting/issue_list_params.py +72 -0
- merge/types/accounting/item.py +54 -0
- merge/types/accounting/item_list_params.py +63 -0
- merge/types/accounting/item_retrieve_params.py +28 -0
- merge/types/accounting/journal_entries/__init__.py +3 -0
- merge/types/accounting/journal_entry.py +701 -0
- merge/types/accounting/journal_entry_create_params.py +699 -0
- merge/types/accounting/journal_entry_list_params.py +63 -0
- merge/types/accounting/journal_entry_response.py +31 -0
- merge/types/accounting/journal_entry_retrieve_params.py +22 -0
- merge/types/accounting/link_token_create_params.py +66 -0
- merge/types/accounting/linked_account_list_params.py +89 -0
- merge/types/accounting/passthrough_request_send_params.py +76 -0
- merge/types/accounting/payment.py +669 -0
- merge/types/accounting/payment_create_params.py +669 -0
- merge/types/accounting/payment_list_params.py +69 -0
- merge/types/accounting/payment_response.py +30 -0
- merge/types/accounting/payment_retrieve_params.py +22 -0
- merge/types/accounting/payments/__init__.py +3 -0
- merge/types/accounting/phone_number.py +19 -0
- merge/types/accounting/phone_number_retrieve_params.py +15 -0
- merge/types/accounting/purchase_order.py +1351 -0
- merge/types/accounting/purchase_order_create_params.py +1346 -0
- merge/types/accounting/purchase_order_list_params.py +69 -0
- merge/types/accounting/purchase_order_response.py +31 -0
- merge/types/accounting/purchase_order_retrieve_params.py +28 -0
- merge/types/accounting/purchase_orders/__init__.py +3 -0
- merge/types/accounting/remote_key_generate_params.py +11 -0
- merge/types/accounting/remote_key_regenerate_params.py +11 -0
- merge/types/accounting/selective_sync_list_configurations_response.py +11 -0
- merge/types/accounting/selective_sync_list_metadata_params.py +17 -0
- merge/types/accounting/selective_sync_replace_configurations_params.py +29 -0
- merge/types/accounting/selective_sync_replace_configurations_response.py +11 -0
- merge/types/accounting/sync_status_list_params.py +15 -0
- merge/types/accounting/sync_status_resync_response.py +9 -0
- merge/types/accounting/tax_rate.py +38 -0
- merge/types/accounting/tax_rate_list_params.py +57 -0
- merge/types/accounting/tax_rate_retrieve_params.py +22 -0
- merge/types/accounting/tracking_category.py +48 -0
- merge/types/accounting/tracking_category_list_params.py +63 -0
- merge/types/accounting/tracking_category_retrieve_params.py +28 -0
- merge/types/accounting/transaction.py +1336 -0
- merge/types/accounting/transaction_list_params.py +63 -0
- merge/types/accounting/transaction_retrieve_params.py +22 -0
- merge/types/accounting/vendor_credit.py +697 -0
- merge/types/accounting/vendor_credit_list_params.py +63 -0
- merge/types/accounting/vendor_credit_retrieve_params.py +22 -0
- merge/types/accounting/webhook_receiver_create_params.py +15 -0
- merge/types/accounting/webhook_receiver_list_response.py +9 -0
- merge/types/ats/__init__.py +125 -0
- merge/types/ats/activities/__init__.py +3 -0
- merge/types/ats/activity.py +53 -0
- merge/types/ats/activity_create_params.py +55 -0
- merge/types/ats/activity_create_response.py +31 -0
- merge/types/ats/activity_list_params.py +63 -0
- merge/types/ats/activity_retrieve_params.py +28 -0
- merge/types/ats/application.py +49 -0
- merge/types/ats/application_change_stage_params.py +15 -0
- merge/types/ats/application_create_params.py +63 -0
- merge/types/ats/application_list_params.py +72 -0
- merge/types/ats/application_response.py +33 -0
- merge/types/ats/application_retrieve_params.py +22 -0
- merge/types/ats/applications/__init__.py +5 -0
- merge/types/ats/applications/meta_for_create_params.py +12 -0
- merge/types/ats/attachment_create_params.py +61 -0
- merge/types/ats/attachment_list_params.py +63 -0
- merge/types/ats/attachment_response.py +28 -0
- merge/types/ats/attachment_retrieve_params.py +28 -0
- merge/types/ats/attachments/__init__.py +3 -0
- merge/types/ats/candidate.py +128 -0
- merge/types/ats/candidate_create_params.py +137 -0
- merge/types/ats/candidate_ignore_row_params.py +18 -0
- merge/types/ats/candidate_list_params.py +72 -0
- merge/types/ats/candidate_response.py +32 -0
- merge/types/ats/candidate_retrieve_params.py +22 -0
- merge/types/ats/candidates/__init__.py +3 -0
- merge/types/ats/common_model_scope_retrieve_params.py +12 -0
- merge/types/ats/common_model_scope_update_params.py +21 -0
- merge/types/ats/department.py +29 -0
- merge/types/ats/department_list_params.py +48 -0
- merge/types/ats/department_retrieve_params.py +15 -0
- merge/types/ats/eeoc.py +94 -0
- merge/types/ats/eeoc_list_params.py +95 -0
- merge/types/ats/eeoc_retrieve_params.py +60 -0
- merge/types/ats/interview_create_params.py +64 -0
- merge/types/ats/interview_list_params.py +69 -0
- merge/types/ats/interview_retrieve_params.py +28 -0
- merge/types/ats/interviews/__init__.py +3 -0
- merge/types/ats/issue_list_params.py +72 -0
- merge/types/ats/job.py +91 -0
- merge/types/ats/job_interview_stage.py +35 -0
- merge/types/ats/job_interview_stage_list_params.py +57 -0
- merge/types/ats/job_interview_stage_retrieve_params.py +22 -0
- merge/types/ats/job_list_params.py +81 -0
- merge/types/ats/job_retrieve_params.py +28 -0
- merge/types/ats/link_token_create_params.py +66 -0
- merge/types/ats/linked_account_list_params.py +89 -0
- merge/types/ats/offer.py +62 -0
- merge/types/ats/offer_list_params.py +66 -0
- merge/types/ats/offer_retrieve_params.py +28 -0
- merge/types/ats/office.py +32 -0
- merge/types/ats/office_list_params.py +48 -0
- merge/types/ats/office_retrieve_params.py +15 -0
- merge/types/ats/passthrough_request_send_params.py +76 -0
- merge/types/ats/reject_reason.py +29 -0
- merge/types/ats/reject_reason_list_params.py +48 -0
- merge/types/ats/reject_reason_retrieve_params.py +15 -0
- merge/types/ats/remote_key_generate_params.py +11 -0
- merge/types/ats/remote_key_regenerate_params.py +11 -0
- merge/types/ats/scheduled_interview.py +61 -0
- merge/types/ats/scheduled_interview_response.py +32 -0
- merge/types/ats/scorecard.py +51 -0
- merge/types/ats/scorecard_list_params.py +69 -0
- merge/types/ats/scorecard_retrieve_params.py +28 -0
- merge/types/ats/selective_sync_list_configurations_response.py +11 -0
- merge/types/ats/selective_sync_list_metadata_params.py +17 -0
- merge/types/ats/selective_sync_replace_configurations_params.py +29 -0
- merge/types/ats/selective_sync_replace_configurations_response.py +11 -0
- merge/types/ats/sync_status_list_params.py +15 -0
- merge/types/ats/sync_status_resync_response.py +9 -0
- merge/types/ats/tag_list_params.py +48 -0
- merge/types/ats/user_list_params.py +57 -0
- merge/types/ats/user_retrieve_params.py +21 -0
- merge/types/ats/webhook_receiver_create_params.py +15 -0
- merge/types/ats/webhook_receiver_list_response.py +9 -0
- merge/types/crm/__init__.py +156 -0
- merge/types/crm/account_create_params.py +706 -0
- merge/types/crm/account_list_params.py +63 -0
- merge/types/crm/account_list_remote_field_classes_params.py +30 -0
- merge/types/crm/account_response.py +28 -0
- merge/types/crm/account_retrieve_params.py +28 -0
- merge/types/crm/account_update_params.py +55 -0
- merge/types/crm/accounts/__init__.py +3 -0
- merge/types/crm/common_model_scope_retrieve_params.py +12 -0
- merge/types/crm/common_model_scope_update_params.py +21 -0
- merge/types/crm/contact_create_params.py +384 -0
- merge/types/crm/contact_ignore_row_params.py +18 -0
- merge/types/crm/contact_list_params.py +63 -0
- merge/types/crm/contact_list_remote_field_classes_params.py +30 -0
- merge/types/crm/contact_response.py +28 -0
- merge/types/crm/contact_retrieve_params.py +28 -0
- merge/types/crm/contact_update_params.py +371 -0
- merge/types/crm/contacts/__init__.py +3 -0
- merge/types/crm/custom_object.py +31 -0
- merge/types/crm/custom_object_class.py +73 -0
- merge/types/crm/custom_object_class_list_params.py +54 -0
- merge/types/crm/custom_object_class_retrieve_params.py +22 -0
- merge/types/crm/custom_object_classes/__init__.py +17 -0
- merge/types/crm/custom_object_classes/association_type.py +46 -0
- merge/types/crm/custom_object_classes/association_type_create_params.py +54 -0
- merge/types/crm/custom_object_classes/association_type_list_params.py +54 -0
- merge/types/crm/custom_object_classes/association_type_response.py +29 -0
- merge/types/crm/custom_object_classes/association_type_retrieve_params.py +22 -0
- merge/types/crm/custom_object_classes/association_types/__init__.py +3 -0
- merge/types/crm/custom_object_create_params.py +15 -0
- merge/types/crm/custom_object_list_params.py +54 -0
- merge/types/crm/custom_object_response.py +29 -0
- merge/types/crm/custom_object_retrieve_params.py +21 -0
- merge/types/crm/custom_object_update_params.py +15 -0
- merge/types/crm/custom_objects/__init__.py +6 -0
- merge/types/crm/custom_objects/association.py +19 -0
- merge/types/crm/custom_objects/association_list_params.py +57 -0
- merge/types/crm/engagement.py +64 -0
- merge/types/crm/engagement_create_params.py +61 -0
- merge/types/crm/engagement_list_params.py +60 -0
- merge/types/crm/engagement_list_remote_field_classes_params.py +30 -0
- merge/types/crm/engagement_response.py +30 -0
- merge/types/crm/engagement_retrieve_params.py +28 -0
- merge/types/crm/engagement_type.py +38 -0
- merge/types/crm/engagement_type_list_params.py +54 -0
- merge/types/crm/engagement_type_list_remote_field_classes_params.py +30 -0
- merge/types/crm/engagement_type_retrieve_params.py +21 -0
- merge/types/crm/engagement_update_params.py +61 -0
- merge/types/crm/engagements/__init__.py +3 -0
- merge/types/crm/issue_list_params.py +72 -0
- merge/types/crm/lead.py +111 -0
- merge/types/crm/lead_create_params.py +386 -0
- merge/types/crm/lead_list_params.py +69 -0
- merge/types/crm/lead_list_remote_field_classes_params.py +30 -0
- merge/types/crm/lead_response.py +30 -0
- merge/types/crm/lead_retrieve_params.py +28 -0
- merge/types/crm/leads/__init__.py +3 -0
- merge/types/crm/link_token_create_params.py +66 -0
- merge/types/crm/linked_account_list_params.py +89 -0
- merge/types/crm/note.py +54 -0
- merge/types/crm/note_create_params.py +43 -0
- merge/types/crm/note_list_params.py +72 -0
- merge/types/crm/note_list_remote_field_classes_params.py +30 -0
- merge/types/crm/note_response.py +29 -0
- merge/types/crm/note_retrieve_params.py +28 -0
- merge/types/crm/notes/__init__.py +3 -0
- merge/types/crm/opportunities/__init__.py +3 -0
- merge/types/crm/opportunity.py +68 -0
- merge/types/crm/opportunity_create_params.py +63 -0
- merge/types/crm/opportunity_list_params.py +85 -0
- merge/types/crm/opportunity_list_remote_field_classes_params.py +30 -0
- merge/types/crm/opportunity_response.py +30 -0
- merge/types/crm/opportunity_retrieve_params.py +34 -0
- merge/types/crm/opportunity_update_params.py +63 -0
- merge/types/crm/passthrough_request_send_params.py +76 -0
- merge/types/crm/remote_key_generate_params.py +11 -0
- merge/types/crm/remote_key_regenerate_params.py +11 -0
- merge/types/crm/selective_sync_list_configurations_response.py +11 -0
- merge/types/crm/selective_sync_list_metadata_params.py +17 -0
- merge/types/crm/selective_sync_replace_configurations_params.py +29 -0
- merge/types/crm/selective_sync_replace_configurations_response.py +11 -0
- merge/types/crm/stage.py +37 -0
- merge/types/crm/stage_list_params.py +54 -0
- merge/types/crm/stage_list_remote_field_classes_params.py +30 -0
- merge/types/crm/stage_retrieve_params.py +21 -0
- merge/types/crm/sync_status_list_params.py +15 -0
- merge/types/crm/sync_status_resync_response.py +9 -0
- merge/types/crm/task.py +59 -0
- merge/types/crm/task_create_params.py +55 -0
- merge/types/crm/task_create_response.py +29 -0
- merge/types/crm/task_list_params.py +60 -0
- merge/types/crm/task_list_remote_field_classes_params.py +30 -0
- merge/types/crm/task_retrieve_params.py +28 -0
- merge/types/crm/task_update_params.py +55 -0
- merge/types/crm/tasks/__init__.py +3 -0
- merge/types/crm/user.py +43 -0
- merge/types/crm/user_ignore_row_params.py +18 -0
- merge/types/crm/user_list_params.py +54 -0
- merge/types/crm/user_list_remote_field_classes_params.py +30 -0
- merge/types/crm/user_retrieve_params.py +21 -0
- merge/types/crm/webhook_receiver_create_params.py +15 -0
- merge/types/crm/webhook_receiver_list_response.py +9 -0
- merge/types/file_storage/__init__.py +65 -0
- merge/types/file_storage/common_model_scope_retrieve_params.py +12 -0
- merge/types/file_storage/common_model_scope_update_params.py +21 -0
- merge/types/file_storage/drive.py +31 -0
- merge/types/file_storage/drive_list_params.py +54 -0
- merge/types/file_storage/drive_retrieve_params.py +15 -0
- merge/types/file_storage/file.py +59 -0
- merge/types/file_storage/file_create_params.py +60 -0
- merge/types/file_storage/file_list_params.py +66 -0
- merge/types/file_storage/file_response.py +30 -0
- merge/types/file_storage/file_retrieve_params.py +22 -0
- merge/types/file_storage/files/__init__.py +3 -0
- merge/types/file_storage/folder.py +53 -0
- merge/types/file_storage/folder_create_params.py +55 -0
- merge/types/file_storage/folder_list_params.py +69 -0
- merge/types/file_storage/folder_response.py +31 -0
- merge/types/file_storage/folder_retrieve_params.py +22 -0
- merge/types/file_storage/folders/__init__.py +3 -0
- merge/types/file_storage/group.py +32 -0
- merge/types/file_storage/group_list_params.py +48 -0
- merge/types/file_storage/group_retrieve_params.py +15 -0
- merge/types/file_storage/issue_list_params.py +72 -0
- merge/types/file_storage/link_token_create_params.py +66 -0
- merge/types/file_storage/linked_account_list_params.py +89 -0
- merge/types/file_storage/passthrough_request_send_params.py +76 -0
- merge/types/file_storage/remote_key_generate_params.py +11 -0
- merge/types/file_storage/remote_key_regenerate_params.py +11 -0
- merge/types/file_storage/selective_sync_list_configurations_response.py +11 -0
- merge/types/file_storage/selective_sync_list_metadata_params.py +17 -0
- merge/types/file_storage/selective_sync_replace_configurations_params.py +29 -0
- merge/types/file_storage/selective_sync_replace_configurations_response.py +11 -0
- merge/types/file_storage/sync_status_list_params.py +15 -0
- merge/types/file_storage/sync_status_resync_response.py +9 -0
- merge/types/file_storage/user.py +31 -0
- merge/types/file_storage/user_list_params.py +48 -0
- merge/types/file_storage/user_retrieve_params.py +15 -0
- merge/types/file_storage/webhook_receiver_create_params.py +15 -0
- merge/types/file_storage/webhook_receiver_list_response.py +9 -0
- merge/types/hris/__init__.py +103 -0
- merge/types/hris/bank_info.py +48 -0
- merge/types/hris/bank_list_params.py +78 -0
- merge/types/hris/bank_retrieve_params.py +28 -0
- merge/types/hris/benefit.py +41 -0
- merge/types/hris/benefit_list_params.py +57 -0
- merge/types/hris/benefit_retrieve_params.py +22 -0
- merge/types/hris/common_model_scope_retrieve_params.py +12 -0
- merge/types/hris/common_model_scope_update_params.py +21 -0
- merge/types/hris/company.py +35 -0
- merge/types/hris/company_list_params.py +48 -0
- merge/types/hris/company_retrieve_params.py +15 -0
- merge/types/hris/created_employee_response.py +31 -0
- merge/types/hris/employee.py +167 -0
- merge/types/hris/employee_create_params.py +164 -0
- merge/types/hris/employee_ignore_params.py +18 -0
- merge/types/hris/employee_list_params.py +162 -0
- merge/types/hris/employee_payroll_run.py +149 -0
- merge/types/hris/employee_payroll_run_list_params.py +77 -0
- merge/types/hris/employee_payroll_run_retrieve_params.py +22 -0
- merge/types/hris/employee_retrieve_params.py +68 -0
- merge/types/hris/employees/__init__.py +3 -0
- merge/types/hris/employment.py +718 -0
- merge/types/hris/employment_list_params.py +98 -0
- merge/types/hris/employment_retrieve_params.py +60 -0
- merge/types/hris/group.py +42 -0
- merge/types/hris/group_list_params.py +60 -0
- merge/types/hris/group_retrieve_params.py +21 -0
- merge/types/hris/issue_list_params.py +72 -0
- merge/types/hris/link_token_create_params.py +66 -0
- merge/types/hris/linked_account_list_params.py +89 -0
- merge/types/hris/location.py +309 -0
- merge/types/hris/location_list_params.py +54 -0
- merge/types/hris/location_retrieve_params.py +21 -0
- merge/types/hris/passthrough_request_send_params.py +76 -0
- merge/types/hris/pay_group.py +29 -0
- merge/types/hris/pay_group_list_params.py +48 -0
- merge/types/hris/pay_group_retrieve_params.py +15 -0
- merge/types/hris/payroll_run.py +54 -0
- merge/types/hris/payroll_run_list_params.py +78 -0
- merge/types/hris/payroll_run_retrieve_params.py +21 -0
- merge/types/hris/remote_key_generate_params.py +11 -0
- merge/types/hris/remote_key_regenerate_params.py +11 -0
- merge/types/hris/selective_sync_list_configurations_response.py +11 -0
- merge/types/hris/selective_sync_list_metadata_params.py +17 -0
- merge/types/hris/selective_sync_replace_configurations_params.py +29 -0
- merge/types/hris/selective_sync_replace_configurations_response.py +11 -0
- merge/types/hris/sync_status_list_params.py +15 -0
- merge/types/hris/sync_status_resync_response.py +9 -0
- merge/types/hris/team_list_params.py +57 -0
- merge/types/hris/team_retrieve_params.py +22 -0
- merge/types/hris/time_off/__init__.py +5 -0
- merge/types/hris/time_off/time_off.py +69 -0
- merge/types/hris/time_off_balance.py +46 -0
- merge/types/hris/time_off_balance_list_params.py +77 -0
- merge/types/hris/time_off_balance_retrieve_params.py +28 -0
- merge/types/hris/time_off_create_params.py +75 -0
- merge/types/hris/time_off_list_params.py +108 -0
- merge/types/hris/time_off_response.py +30 -0
- merge/types/hris/time_off_retrieve_params.py +44 -0
- merge/types/hris/webhook_receiver_create_params.py +15 -0
- merge/types/hris/webhook_receiver_list_response.py +9 -0
- merge/types/marketing/__init__.py +113 -0
- merge/types/marketing/action.py +41 -0
- merge/types/marketing/action_create_params.py +44 -0
- merge/types/marketing/action_list_params.py +48 -0
- merge/types/marketing/action_response.py +30 -0
- merge/types/marketing/action_retrieve_params.py +15 -0
- merge/types/marketing/actions/__init__.py +3 -0
- merge/types/marketing/automation.py +53 -0
- merge/types/marketing/automation_create_params.py +60 -0
- merge/types/marketing/automation_list_params.py +48 -0
- merge/types/marketing/automation_list_recipients_params.py +24 -0
- merge/types/marketing/automation_response.py +31 -0
- merge/types/marketing/automation_retrieve_params.py +15 -0
- merge/types/marketing/automations/__init__.py +3 -0
- merge/types/marketing/campaign.py +38 -0
- merge/types/marketing/campaign_create_params.py +39 -0
- merge/types/marketing/campaign_list_contacts_params.py +24 -0
- merge/types/marketing/campaign_list_params.py +48 -0
- merge/types/marketing/campaign_response.py +31 -0
- merge/types/marketing/campaign_retrieve_params.py +15 -0
- merge/types/marketing/campaigns/__init__.py +3 -0
- merge/types/marketing/common_model_scope_retrieve_params.py +12 -0
- merge/types/marketing/common_model_scope_update_params.py +21 -0
- merge/types/marketing/contact_create_params.py +384 -0
- merge/types/marketing/contact_list.py +38 -0
- merge/types/marketing/contact_list_create_params.py +34 -0
- merge/types/marketing/contact_list_create_response.py +29 -0
- merge/types/marketing/contact_list_list_params.py +48 -0
- merge/types/marketing/contact_list_list_subscribers_params.py +24 -0
- merge/types/marketing/contact_list_params.py +48 -0
- merge/types/marketing/contact_list_retrieve_params.py +15 -0
- merge/types/marketing/contact_lists/__init__.py +3 -0
- merge/types/marketing/contact_response.py +28 -0
- merge/types/marketing/contact_retrieve_params.py +15 -0
- merge/types/marketing/contacts/__init__.py +3 -0
- merge/types/marketing/email.py +73 -0
- merge/types/marketing/email_list_params.py +48 -0
- merge/types/marketing/email_list_recipients_params.py +24 -0
- merge/types/marketing/email_retrieve_params.py +15 -0
- merge/types/marketing/event.py +47 -0
- merge/types/marketing/event_list_contacts_params.py +24 -0
- merge/types/marketing/event_list_params.py +48 -0
- merge/types/marketing/event_retrieve_params.py +15 -0
- merge/types/marketing/issue_list_params.py +72 -0
- merge/types/marketing/link_token_create_params.py +66 -0
- merge/types/marketing/linked_account_list_params.py +89 -0
- merge/types/marketing/message.py +35 -0
- merge/types/marketing/message_list_params.py +48 -0
- merge/types/marketing/message_list_recipients_params.py +24 -0
- merge/types/marketing/message_retrieve_params.py +15 -0
- merge/types/marketing/passthrough_request_send_params.py +76 -0
- merge/types/marketing/remote_key_generate_params.py +11 -0
- merge/types/marketing/remote_key_regenerate_params.py +11 -0
- merge/types/marketing/selective_sync_list_configurations_response.py +11 -0
- merge/types/marketing/selective_sync_list_metadata_params.py +17 -0
- merge/types/marketing/selective_sync_replace_configurations_params.py +29 -0
- merge/types/marketing/selective_sync_replace_configurations_response.py +11 -0
- merge/types/marketing/sync_status_list_params.py +15 -0
- merge/types/marketing/sync_status_resync_response.py +9 -0
- merge/types/marketing/template.py +48 -0
- merge/types/marketing/template_create_params.py +45 -0
- merge/types/marketing/template_list_params.py +48 -0
- merge/types/marketing/template_response.py +31 -0
- merge/types/marketing/template_retrieve_params.py +15 -0
- merge/types/marketing/templates/__init__.py +3 -0
- merge/types/marketing/user.py +47 -0
- merge/types/marketing/user_list_params.py +48 -0
- merge/types/marketing/user_retrieve_params.py +15 -0
- merge/types/marketing/webhook_receiver_create_params.py +15 -0
- merge/types/marketing/webhook_receiver_list_response.py +9 -0
- merge/types/shared/__init__.py +33 -0
- merge/types/shared/account.py +745 -0
- merge/types/shared/account_detail.py +45 -0
- merge/types/shared/account_details_and_actions.py +78 -0
- merge/types/shared/account_token.py +56 -0
- merge/types/shared/address.py +303 -0
- merge/types/shared/attachment.py +60 -0
- merge/types/shared/available_action.py +68 -0
- merge/types/shared/common_model_scope.py +56 -0
- merge/types/shared/condition_schema.py +56 -0
- merge/types/shared/contact.py +397 -0
- merge/types/shared/country.py +257 -0
- merge/types/shared/debug_log.py +22 -0
- merge/types/shared/issue.py +31 -0
- merge/types/shared/link_token.py +15 -0
- merge/types/shared/linked_account_selective_sync_configuration.py +35 -0
- merge/types/shared/meta_response.py +25 -0
- merge/types/shared/remote_data.py +13 -0
- merge/types/shared/remote_field_class.py +54 -0
- merge/types/shared/remote_key.py +12 -0
- merge/types/shared/remote_response.py +28 -0
- merge/types/shared/remote_user.py +51 -0
- merge/types/shared/sync_status.py +36 -0
- merge/types/shared/tag.py +27 -0
- merge/types/shared/team.py +35 -0
- merge/types/shared/validation_error.py +21 -0
- merge/types/shared/validation_warning.py +21 -0
- merge/types/shared/webhook_receiver.py +15 -0
- merge/types/shared_params/__init__.py +33 -0
- merge/types/shared_params/account.py +700 -0
- merge/types/shared_params/account_detail.py +20 -0
- merge/types/shared_params/account_details_and_actions.py +78 -0
- merge/types/shared_params/account_token.py +54 -0
- merge/types/shared_params/address.py +295 -0
- merge/types/shared_params/attachment.py +50 -0
- merge/types/shared_params/available_action.py +66 -0
- merge/types/shared_params/common_model_scope.py +56 -0
- merge/types/shared_params/condition_schema.py +49 -0
- merge/types/shared_params/contact.py +374 -0
- merge/types/shared_params/country.py +259 -0
- merge/types/shared_params/debug_log.py +23 -0
- merge/types/shared_params/issue.py +25 -0
- merge/types/shared_params/link_token.py +15 -0
- merge/types/shared_params/linked_account_selective_sync_configuration.py +11 -0
- merge/types/shared_params/meta_response.py +25 -0
- merge/types/shared_params/remote_data.py +13 -0
- merge/types/shared_params/remote_field_class.py +54 -0
- merge/types/shared_params/remote_key.py +13 -0
- merge/types/shared_params/remote_response.py +27 -0
- merge/types/shared_params/remote_user.py +40 -0
- merge/types/shared_params/sync_status.py +38 -0
- merge/types/shared_params/tag.py +19 -0
- merge/types/shared_params/team.py +22 -0
- merge/types/shared_params/validation_error.py +21 -0
- merge/types/shared_params/validation_warning.py +21 -0
- merge/types/shared_params/webhook_receiver.py +15 -0
- merge/types/ticketing/__init__.py +94 -0
- merge/types/ticketing/account_list_params.py +48 -0
- merge/types/ticketing/account_retrieve_params.py +15 -0
- merge/types/ticketing/attachment_create_params.py +59 -0
- merge/types/ticketing/attachment_create_response.py +28 -0
- merge/types/ticketing/attachment_list_params.py +57 -0
- merge/types/ticketing/attachment_retrieve_params.py +22 -0
- merge/types/ticketing/attachments/__init__.py +3 -0
- merge/types/ticketing/collection.py +42 -0
- merge/types/ticketing/collection_list_params.py +73 -0
- merge/types/ticketing/collection_list_users_params.py +31 -0
- merge/types/ticketing/collection_retrieve_params.py +28 -0
- merge/types/ticketing/comment.py +46 -0
- merge/types/ticketing/comment_create_params.py +46 -0
- merge/types/ticketing/comment_list_params.py +57 -0
- merge/types/ticketing/comment_response.py +29 -0
- merge/types/ticketing/comment_retrieve_params.py +22 -0
- merge/types/ticketing/comments/__init__.py +3 -0
- merge/types/ticketing/common_model_scope_retrieve_params.py +12 -0
- merge/types/ticketing/common_model_scope_update_params.py +21 -0
- merge/types/ticketing/contact_list_params.py +54 -0
- merge/types/ticketing/contact_retrieve_params.py +22 -0
- merge/types/ticketing/issue_list_params.py +72 -0
- merge/types/ticketing/link_token_create_params.py +66 -0
- merge/types/ticketing/linked_account_list_params.py +89 -0
- merge/types/ticketing/passthrough_request_send_params.py +76 -0
- merge/types/ticketing/project.py +32 -0
- merge/types/ticketing/project_list_params.py +48 -0
- merge/types/ticketing/project_list_users_params.py +31 -0
- merge/types/ticketing/project_retrieve_params.py +15 -0
- merge/types/ticketing/remote_key_generate_params.py +11 -0
- merge/types/ticketing/remote_key_regenerate_params.py +11 -0
- merge/types/ticketing/selective_sync_list_configurations_response.py +11 -0
- merge/types/ticketing/selective_sync_list_metadata_params.py +17 -0
- merge/types/ticketing/selective_sync_replace_configurations_params.py +29 -0
- merge/types/ticketing/selective_sync_replace_configurations_response.py +11 -0
- merge/types/ticketing/sync_status_list_params.py +15 -0
- merge/types/ticketing/sync_status_resync_response.py +9 -0
- merge/types/ticketing/tag_list_params.py +48 -0
- merge/types/ticketing/tag_retrieve_params.py +15 -0
- merge/types/ticketing/team_list_params.py +48 -0
- merge/types/ticketing/team_retrieve_params.py +15 -0
- merge/types/ticketing/ticket.py +100 -0
- merge/types/ticketing/ticket_create_params.py +91 -0
- merge/types/ticketing/ticket_list_collaborators_params.py +31 -0
- merge/types/ticketing/ticket_list_params.py +171 -0
- merge/types/ticketing/ticket_list_remote_field_classes_params.py +24 -0
- merge/types/ticketing/ticket_response.py +29 -0
- merge/types/ticketing/ticket_retrieve_params.py +52 -0
- merge/types/ticketing/ticket_update_params.py +89 -0
- merge/types/ticketing/tickets/__init__.py +3 -0
- merge/types/ticketing/user.py +40 -0
- merge/types/ticketing/user_list_params.py +60 -0
- merge/types/ticketing/user_retrieve_params.py +22 -0
- merge/types/ticketing/webhook_receiver_create_params.py +15 -0
- merge/types/ticketing/webhook_receiver_list_response.py +9 -0
- mergepythonclient-0.0.1.dist-info/LICENSE.md +16 -0
- mergepythonclient-0.0.1.dist-info/METADATA +281 -0
- mergepythonclient-0.0.1.dist-info/RECORD +834 -0
- mergepythonclient-0.0.1.dist-info/WHEEL +4 -0
merge/_base_client.py
ADDED
|
@@ -0,0 +1,1431 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import time
|
|
5
|
+
import uuid
|
|
6
|
+
import inspect
|
|
7
|
+
import platform
|
|
8
|
+
from random import random
|
|
9
|
+
from typing import (
|
|
10
|
+
Any,
|
|
11
|
+
Dict,
|
|
12
|
+
List,
|
|
13
|
+
Type,
|
|
14
|
+
Union,
|
|
15
|
+
Generic,
|
|
16
|
+
Mapping,
|
|
17
|
+
TypeVar,
|
|
18
|
+
Iterable,
|
|
19
|
+
Iterator,
|
|
20
|
+
Optional,
|
|
21
|
+
Generator,
|
|
22
|
+
AsyncIterator,
|
|
23
|
+
cast,
|
|
24
|
+
overload,
|
|
25
|
+
)
|
|
26
|
+
from functools import lru_cache
|
|
27
|
+
from typing_extensions import Literal, get_origin
|
|
28
|
+
|
|
29
|
+
import anyio
|
|
30
|
+
import httpx
|
|
31
|
+
import distro
|
|
32
|
+
import pydantic
|
|
33
|
+
from httpx import URL, Limits
|
|
34
|
+
from pydantic import PrivateAttr
|
|
35
|
+
|
|
36
|
+
from . import _base_exceptions as exceptions
|
|
37
|
+
from ._qs import Querystring
|
|
38
|
+
from ._types import (
|
|
39
|
+
NOT_GIVEN,
|
|
40
|
+
Body,
|
|
41
|
+
Omit,
|
|
42
|
+
Query,
|
|
43
|
+
ModelT,
|
|
44
|
+
Headers,
|
|
45
|
+
Timeout,
|
|
46
|
+
NoneType,
|
|
47
|
+
NotGiven,
|
|
48
|
+
Transport,
|
|
49
|
+
AnyMapping,
|
|
50
|
+
ProxiesTypes,
|
|
51
|
+
RequestFiles,
|
|
52
|
+
RequestOptions,
|
|
53
|
+
UnknownResponse,
|
|
54
|
+
ModelBuilderProtocol,
|
|
55
|
+
)
|
|
56
|
+
from ._utils import is_dict, is_mapping
|
|
57
|
+
from ._models import (
|
|
58
|
+
BaseModel,
|
|
59
|
+
GenericModel,
|
|
60
|
+
FinalRequestOptions,
|
|
61
|
+
validate_type,
|
|
62
|
+
construct_type,
|
|
63
|
+
)
|
|
64
|
+
from ._base_exceptions import (
|
|
65
|
+
APIStatusError,
|
|
66
|
+
APITimeoutError,
|
|
67
|
+
APIConnectionError,
|
|
68
|
+
APIResponseValidationError,
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
# TODO: make base page type vars covariant
|
|
72
|
+
SyncPageT = TypeVar("SyncPageT", bound="BaseSyncPage[Any]")
|
|
73
|
+
AsyncPageT = TypeVar("AsyncPageT", bound="BaseAsyncPage[Any]")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
ResponseT = TypeVar(
|
|
77
|
+
"ResponseT",
|
|
78
|
+
bound=Union[
|
|
79
|
+
str,
|
|
80
|
+
None,
|
|
81
|
+
BaseModel,
|
|
82
|
+
List[Any],
|
|
83
|
+
Dict[str, Any],
|
|
84
|
+
httpx.Response,
|
|
85
|
+
UnknownResponse,
|
|
86
|
+
ModelBuilderProtocol,
|
|
87
|
+
],
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
_T = TypeVar("_T")
|
|
91
|
+
_T_co = TypeVar("_T_co", covariant=True)
|
|
92
|
+
|
|
93
|
+
DEFAULT_TIMEOUT = Timeout(timeout=60.0, connect=5.0)
|
|
94
|
+
DEFAULT_MAX_RETRIES = 2
|
|
95
|
+
DEFAULT_LIMITS = Limits(max_connections=100, max_keepalive_connections=20)
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
class StopStreaming(Exception):
|
|
99
|
+
"""Raised internally when processing of a streamed response should be stopped."""
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class Stream(Generic[ResponseT]):
|
|
103
|
+
response: httpx.Response
|
|
104
|
+
|
|
105
|
+
def __init__(
|
|
106
|
+
self,
|
|
107
|
+
*,
|
|
108
|
+
cast_to: type[ResponseT],
|
|
109
|
+
response: httpx.Response,
|
|
110
|
+
client: SyncAPIClient,
|
|
111
|
+
) -> None:
|
|
112
|
+
self.response = response
|
|
113
|
+
self._cast_to = cast_to
|
|
114
|
+
self._client = client
|
|
115
|
+
self._iterator = self.__iter()
|
|
116
|
+
|
|
117
|
+
def __next__(self) -> ResponseT:
|
|
118
|
+
return self._iterator.__next__()
|
|
119
|
+
|
|
120
|
+
def __iter__(self) -> Iterator[ResponseT]:
|
|
121
|
+
for item in self._iterator:
|
|
122
|
+
yield item
|
|
123
|
+
|
|
124
|
+
def __iter(self) -> Iterator[ResponseT]:
|
|
125
|
+
cast_to = self._cast_to
|
|
126
|
+
response = self.response
|
|
127
|
+
process_line = self._client._process_stream_line
|
|
128
|
+
process_data = self._client._process_response_data
|
|
129
|
+
|
|
130
|
+
awaiting_ping_data = False
|
|
131
|
+
for raw_line in response.iter_lines():
|
|
132
|
+
if not raw_line or raw_line == "\n":
|
|
133
|
+
continue
|
|
134
|
+
|
|
135
|
+
if raw_line.startswith("event: ping"):
|
|
136
|
+
awaiting_ping_data = True
|
|
137
|
+
continue
|
|
138
|
+
if awaiting_ping_data:
|
|
139
|
+
awaiting_ping_data = False
|
|
140
|
+
continue
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
line = process_line(raw_line)
|
|
144
|
+
except StopStreaming:
|
|
145
|
+
# we are done!
|
|
146
|
+
break
|
|
147
|
+
|
|
148
|
+
yield process_data(data=json.loads(line), cast_to=cast_to, response=response)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class AsyncStream(Generic[ResponseT]):
|
|
152
|
+
response: httpx.Response
|
|
153
|
+
|
|
154
|
+
def __init__(
|
|
155
|
+
self,
|
|
156
|
+
*,
|
|
157
|
+
cast_to: type[ResponseT],
|
|
158
|
+
response: httpx.Response,
|
|
159
|
+
client: AsyncAPIClient,
|
|
160
|
+
) -> None:
|
|
161
|
+
self.response = response
|
|
162
|
+
self._cast_to = cast_to
|
|
163
|
+
self._client = client
|
|
164
|
+
self._iterator = self.__iter()
|
|
165
|
+
|
|
166
|
+
async def __anext__(self) -> ResponseT:
|
|
167
|
+
return await self._iterator.__anext__()
|
|
168
|
+
|
|
169
|
+
async def __aiter__(self) -> AsyncIterator[ResponseT]:
|
|
170
|
+
async for item in self._iterator:
|
|
171
|
+
yield item
|
|
172
|
+
|
|
173
|
+
async def __iter(self) -> AsyncIterator[ResponseT]:
|
|
174
|
+
cast_to = self._cast_to
|
|
175
|
+
response = self.response
|
|
176
|
+
process_line = self._client._process_stream_line
|
|
177
|
+
process_data = self._client._process_response_data
|
|
178
|
+
|
|
179
|
+
awaiting_ping_data = False
|
|
180
|
+
async for raw_line in response.aiter_lines():
|
|
181
|
+
if not raw_line or raw_line == "\n":
|
|
182
|
+
continue
|
|
183
|
+
|
|
184
|
+
if raw_line.startswith("event: ping"):
|
|
185
|
+
awaiting_ping_data = True
|
|
186
|
+
continue
|
|
187
|
+
if awaiting_ping_data:
|
|
188
|
+
awaiting_ping_data = False
|
|
189
|
+
continue
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
line = process_line(raw_line)
|
|
193
|
+
except StopStreaming:
|
|
194
|
+
# we are done!
|
|
195
|
+
break
|
|
196
|
+
|
|
197
|
+
yield process_data(data=json.loads(line), cast_to=cast_to, response=response)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
class PageInfo:
|
|
201
|
+
"""Stores the necesary information to build the request to retrieve the next page.
|
|
202
|
+
|
|
203
|
+
Either `url` or `params` must be set.
|
|
204
|
+
"""
|
|
205
|
+
|
|
206
|
+
url: URL | NotGiven
|
|
207
|
+
params: Query | NotGiven
|
|
208
|
+
|
|
209
|
+
@overload
|
|
210
|
+
def __init__(
|
|
211
|
+
self,
|
|
212
|
+
*,
|
|
213
|
+
url: URL,
|
|
214
|
+
) -> None:
|
|
215
|
+
...
|
|
216
|
+
|
|
217
|
+
@overload
|
|
218
|
+
def __init__(
|
|
219
|
+
self,
|
|
220
|
+
*,
|
|
221
|
+
params: Query,
|
|
222
|
+
) -> None:
|
|
223
|
+
...
|
|
224
|
+
|
|
225
|
+
def __init__(
|
|
226
|
+
self,
|
|
227
|
+
*,
|
|
228
|
+
url: URL | NotGiven = NOT_GIVEN,
|
|
229
|
+
params: Query | NotGiven = NOT_GIVEN,
|
|
230
|
+
) -> None:
|
|
231
|
+
self.url = url
|
|
232
|
+
self.params = params
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class BasePage(GenericModel, Generic[ModelT]):
|
|
236
|
+
_options: FinalRequestOptions = PrivateAttr()
|
|
237
|
+
_model: Type[ModelT] = PrivateAttr()
|
|
238
|
+
|
|
239
|
+
def has_next_page(self) -> bool:
|
|
240
|
+
items = self._get_page_items()
|
|
241
|
+
if not items:
|
|
242
|
+
return False
|
|
243
|
+
return self.next_page_info() is not None
|
|
244
|
+
|
|
245
|
+
def next_page_info(self) -> Optional[PageInfo]:
|
|
246
|
+
...
|
|
247
|
+
|
|
248
|
+
def _get_page_items(self) -> Iterable[ModelT]: # type: ignore[empty-body]
|
|
249
|
+
...
|
|
250
|
+
|
|
251
|
+
def _params_from_url(self, url: URL) -> httpx.QueryParams:
|
|
252
|
+
# TODO: do we have to preprocess params here?
|
|
253
|
+
return httpx.QueryParams(cast(Any, self._options.params)).merge(url.params)
|
|
254
|
+
|
|
255
|
+
def _info_to_options(self, info: PageInfo) -> FinalRequestOptions:
|
|
256
|
+
options = self._options.copy()
|
|
257
|
+
|
|
258
|
+
if not isinstance(info.params, NotGiven):
|
|
259
|
+
options.params = {**options.params, **info.params}
|
|
260
|
+
return options
|
|
261
|
+
|
|
262
|
+
if not isinstance(info.url, NotGiven):
|
|
263
|
+
params = self._params_from_url(info.url)
|
|
264
|
+
url = info.url.copy_with(params=params)
|
|
265
|
+
options.params = dict(url.params)
|
|
266
|
+
options.url = str(url)
|
|
267
|
+
return options
|
|
268
|
+
|
|
269
|
+
raise ValueError("Unexpected PageInfo state")
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
class BaseSyncPage(BasePage[ModelT], Generic[ModelT]):
|
|
273
|
+
_client: SyncAPIClient = pydantic.PrivateAttr()
|
|
274
|
+
|
|
275
|
+
def _set_private_attributes(
|
|
276
|
+
self,
|
|
277
|
+
client: SyncAPIClient,
|
|
278
|
+
model: Type[ModelT],
|
|
279
|
+
options: FinalRequestOptions,
|
|
280
|
+
) -> None:
|
|
281
|
+
self._model = model
|
|
282
|
+
self._client = client
|
|
283
|
+
self._options = options
|
|
284
|
+
|
|
285
|
+
# Pydantic uses a custom `__iter__` method to support casting BaseModels
|
|
286
|
+
# to dictionaries. e.g. dict(model).
|
|
287
|
+
# As we want to support `for item in page`, this is inherently incompatible
|
|
288
|
+
# with the default pydantic behaviour. It is not possible to support both
|
|
289
|
+
# use cases at once. Fortunately, this is not a big deal as all other pydantic
|
|
290
|
+
# methods should continue to work as expected as there is an alternative method
|
|
291
|
+
# to cast a model to a dictionary, model.dict(), which is used internally
|
|
292
|
+
# by pydantic.
|
|
293
|
+
def __iter__(self) -> Iterator[ModelT]: # type: ignore
|
|
294
|
+
for page in self.iter_pages():
|
|
295
|
+
for item in page._get_page_items():
|
|
296
|
+
yield item
|
|
297
|
+
|
|
298
|
+
def iter_pages(self: SyncPageT) -> Iterator[SyncPageT]:
|
|
299
|
+
page = self
|
|
300
|
+
while True:
|
|
301
|
+
yield page
|
|
302
|
+
if page.has_next_page():
|
|
303
|
+
page = page.get_next_page()
|
|
304
|
+
else:
|
|
305
|
+
return
|
|
306
|
+
|
|
307
|
+
def get_next_page(self: SyncPageT) -> SyncPageT:
|
|
308
|
+
info = self.next_page_info()
|
|
309
|
+
if not info:
|
|
310
|
+
raise RuntimeError(
|
|
311
|
+
"No next page expected; please check `.has_next_page()` before calling `.get_next_page()`."
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
options = self._info_to_options(info)
|
|
315
|
+
return self._client._request_api_list(self._model, page=self.__class__, options=options)
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
class AsyncPaginator(Generic[ModelT, AsyncPageT]):
|
|
319
|
+
def __init__(
|
|
320
|
+
self,
|
|
321
|
+
client: AsyncAPIClient,
|
|
322
|
+
options: FinalRequestOptions,
|
|
323
|
+
page_cls: Type[AsyncPageT],
|
|
324
|
+
model: Type[ModelT],
|
|
325
|
+
) -> None:
|
|
326
|
+
self._model = model
|
|
327
|
+
self._client = client
|
|
328
|
+
self._options = options
|
|
329
|
+
self._page_cls = page_cls
|
|
330
|
+
|
|
331
|
+
def __await__(self) -> Generator[Any, None, AsyncPageT]:
|
|
332
|
+
return self._get_page().__await__()
|
|
333
|
+
|
|
334
|
+
async def _get_page(self) -> AsyncPageT:
|
|
335
|
+
page = await self._client.request(self._page_cls, self._options)
|
|
336
|
+
page._set_private_attributes( # pyright: ignore[reportPrivateUsage]
|
|
337
|
+
model=self._model,
|
|
338
|
+
options=self._options,
|
|
339
|
+
client=self._client,
|
|
340
|
+
)
|
|
341
|
+
return page
|
|
342
|
+
|
|
343
|
+
async def __aiter__(self) -> AsyncIterator[ModelT]:
|
|
344
|
+
# https://github.com/microsoft/pyright/issues/3464
|
|
345
|
+
page = cast(
|
|
346
|
+
AsyncPageT,
|
|
347
|
+
await self, # type: ignore
|
|
348
|
+
)
|
|
349
|
+
async for item in page:
|
|
350
|
+
yield item
|
|
351
|
+
|
|
352
|
+
|
|
353
|
+
class BaseAsyncPage(BasePage[ModelT], Generic[ModelT]):
|
|
354
|
+
_client: AsyncAPIClient = pydantic.PrivateAttr()
|
|
355
|
+
|
|
356
|
+
def _set_private_attributes(
|
|
357
|
+
self,
|
|
358
|
+
model: Type[ModelT],
|
|
359
|
+
client: AsyncAPIClient,
|
|
360
|
+
options: FinalRequestOptions,
|
|
361
|
+
) -> None:
|
|
362
|
+
self._model = model
|
|
363
|
+
self._client = client
|
|
364
|
+
self._options = options
|
|
365
|
+
|
|
366
|
+
async def __aiter__(self) -> AsyncIterator[ModelT]:
|
|
367
|
+
async for page in self.iter_pages():
|
|
368
|
+
for item in page._get_page_items():
|
|
369
|
+
yield item
|
|
370
|
+
|
|
371
|
+
async def iter_pages(self: AsyncPageT) -> AsyncIterator[AsyncPageT]:
|
|
372
|
+
page = self
|
|
373
|
+
while True:
|
|
374
|
+
yield page
|
|
375
|
+
if page.has_next_page():
|
|
376
|
+
page = await page.get_next_page()
|
|
377
|
+
else:
|
|
378
|
+
return
|
|
379
|
+
|
|
380
|
+
async def get_next_page(self: AsyncPageT) -> AsyncPageT:
|
|
381
|
+
info = self.next_page_info()
|
|
382
|
+
if not info:
|
|
383
|
+
raise RuntimeError(
|
|
384
|
+
"No next page expected; please check `.has_next_page()` before calling `.get_next_page()`."
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
options = self._info_to_options(info)
|
|
388
|
+
return await self._client._request_api_list(self._model, page=self.__class__, options=options)
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
class BaseClient:
|
|
392
|
+
_client: httpx.Client | httpx.AsyncClient
|
|
393
|
+
_version: str
|
|
394
|
+
max_retries: int
|
|
395
|
+
timeout: Union[float, Timeout, None]
|
|
396
|
+
_limits: httpx.Limits
|
|
397
|
+
_strict_response_validation: bool
|
|
398
|
+
_idempotency_header: str | None
|
|
399
|
+
|
|
400
|
+
def __init__(
|
|
401
|
+
self,
|
|
402
|
+
*,
|
|
403
|
+
version: str,
|
|
404
|
+
_strict_response_validation: bool,
|
|
405
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
406
|
+
timeout: float | Timeout | None = DEFAULT_TIMEOUT,
|
|
407
|
+
limits: httpx.Limits,
|
|
408
|
+
custom_headers: Mapping[str, str] | None = None,
|
|
409
|
+
custom_query: Mapping[str, object] | None = None,
|
|
410
|
+
) -> None:
|
|
411
|
+
self._version = version
|
|
412
|
+
self.max_retries = max_retries
|
|
413
|
+
self.timeout = timeout
|
|
414
|
+
self._limits = limits
|
|
415
|
+
self._custom_headers = custom_headers or {}
|
|
416
|
+
self._custom_query = custom_query or {}
|
|
417
|
+
self._strict_response_validation = _strict_response_validation
|
|
418
|
+
self._idempotency_header = None
|
|
419
|
+
|
|
420
|
+
def _make_status_error_from_response(
|
|
421
|
+
self,
|
|
422
|
+
request: httpx.Request,
|
|
423
|
+
response: httpx.Response,
|
|
424
|
+
) -> APIStatusError:
|
|
425
|
+
err_text = response.text.strip()
|
|
426
|
+
body = err_text
|
|
427
|
+
|
|
428
|
+
try:
|
|
429
|
+
body = json.loads(err_text)
|
|
430
|
+
err_msg = f"Error code: {response.status_code} - {body}"
|
|
431
|
+
except Exception:
|
|
432
|
+
err_msg = err_text or f"Error code: {response.status_code}"
|
|
433
|
+
|
|
434
|
+
return self._make_status_error(err_msg, body=body, request=request, response=response)
|
|
435
|
+
|
|
436
|
+
def _make_status_error(
|
|
437
|
+
self,
|
|
438
|
+
err_msg: str,
|
|
439
|
+
*,
|
|
440
|
+
body: object,
|
|
441
|
+
request: httpx.Request,
|
|
442
|
+
response: httpx.Response,
|
|
443
|
+
) -> APIStatusError:
|
|
444
|
+
if response.status_code == 400:
|
|
445
|
+
return exceptions.BadRequestError(err_msg, request=request, response=response, body=body)
|
|
446
|
+
if response.status_code == 401:
|
|
447
|
+
return exceptions.AuthenticationError(err_msg, request=request, response=response, body=body)
|
|
448
|
+
if response.status_code == 403:
|
|
449
|
+
return exceptions.PermissionDeniedError(err_msg, request=request, response=response, body=body)
|
|
450
|
+
if response.status_code == 404:
|
|
451
|
+
return exceptions.NotFoundError(err_msg, request=request, response=response, body=body)
|
|
452
|
+
if response.status_code == 409:
|
|
453
|
+
return exceptions.ConflictError(err_msg, request=request, response=response, body=body)
|
|
454
|
+
if response.status_code == 422:
|
|
455
|
+
return exceptions.UnprocessableEntityError(err_msg, request=request, response=response, body=body)
|
|
456
|
+
if response.status_code == 429:
|
|
457
|
+
return exceptions.RateLimitError(err_msg, request=request, response=response, body=body)
|
|
458
|
+
if response.status_code >= 500:
|
|
459
|
+
return exceptions.InternalServerError(err_msg, request=request, response=response, body=body)
|
|
460
|
+
return APIStatusError(err_msg, request=request, response=response, body=body)
|
|
461
|
+
|
|
462
|
+
def _remaining_retries(
|
|
463
|
+
self,
|
|
464
|
+
remaining_retries: Optional[int],
|
|
465
|
+
options: FinalRequestOptions,
|
|
466
|
+
) -> int:
|
|
467
|
+
return remaining_retries if remaining_retries is not None else options.get_max_retries(self.max_retries)
|
|
468
|
+
|
|
469
|
+
def _build_headers(self, options: FinalRequestOptions) -> httpx.Headers:
|
|
470
|
+
custom_headers = options.headers or {}
|
|
471
|
+
headers_dict = _merge_mappings(self.default_headers, custom_headers)
|
|
472
|
+
self._validate_headers(headers_dict, custom_headers)
|
|
473
|
+
|
|
474
|
+
headers = httpx.Headers(headers_dict)
|
|
475
|
+
|
|
476
|
+
idempotency_header = self._idempotency_header
|
|
477
|
+
if idempotency_header and options.method.lower() != "get" and idempotency_header not in headers:
|
|
478
|
+
if not options.idempotency_key:
|
|
479
|
+
options.idempotency_key = self._idempotency_key()
|
|
480
|
+
|
|
481
|
+
headers[idempotency_header] = options.idempotency_key
|
|
482
|
+
|
|
483
|
+
return headers
|
|
484
|
+
|
|
485
|
+
def _build_request(
|
|
486
|
+
self,
|
|
487
|
+
options: FinalRequestOptions,
|
|
488
|
+
) -> httpx.Request:
|
|
489
|
+
headers = self._build_headers(options)
|
|
490
|
+
|
|
491
|
+
kwargs: dict[str, Any] = {}
|
|
492
|
+
|
|
493
|
+
json_data = options.json_data
|
|
494
|
+
if options.extra_json is not None:
|
|
495
|
+
if json_data is None:
|
|
496
|
+
json_data = cast(Body, options.extra_json)
|
|
497
|
+
elif is_mapping(json_data):
|
|
498
|
+
json_data = _merge_mappings(json_data, options.extra_json)
|
|
499
|
+
else:
|
|
500
|
+
raise RuntimeError(f"Unexpected JSON data type, {type(json_data)}, cannot merge with `extra_body`")
|
|
501
|
+
|
|
502
|
+
params = _merge_mappings(self._custom_query, options.params)
|
|
503
|
+
|
|
504
|
+
# If the given Content-Type header is multipart/form-data then it
|
|
505
|
+
# has to be removed so that httpx can generate the header with
|
|
506
|
+
# additional information for us as it has to be in this form
|
|
507
|
+
# for the server to be able to correctly parse the request:
|
|
508
|
+
# multipart/form-data; boundary=---abc--
|
|
509
|
+
if headers.get("Content-Type") == "multipart/form-data":
|
|
510
|
+
headers.pop("Content-Type")
|
|
511
|
+
|
|
512
|
+
# As we are now sending multipart/form-data instead of application/json
|
|
513
|
+
# we need to tell httpx to use it, https://www.python-httpx.org/advanced/#multipart-file-encoding
|
|
514
|
+
if json_data:
|
|
515
|
+
if not is_dict(json_data):
|
|
516
|
+
raise TypeError(
|
|
517
|
+
f"Expected query input to be a dictionary for multipart requests but got {type(json_data)} instead."
|
|
518
|
+
)
|
|
519
|
+
kwargs["data"] = self._serialize_multipartform(json_data)
|
|
520
|
+
|
|
521
|
+
# TODO: report this error to httpx
|
|
522
|
+
return self._client.build_request( # pyright: ignore[reportUnknownMemberType]
|
|
523
|
+
headers=headers,
|
|
524
|
+
timeout=self.timeout if isinstance(options.timeout, NotGiven) else options.timeout,
|
|
525
|
+
method=options.method,
|
|
526
|
+
url=options.url,
|
|
527
|
+
# the `Query` type that we use is incompatible with qs'
|
|
528
|
+
# `Params` type as it needs to be typed as `Mapping[str, object]`
|
|
529
|
+
# so that passing a `TypedDict` doesn't cause an error.
|
|
530
|
+
# https://github.com/microsoft/pyright/issues/3526#event-6715453066
|
|
531
|
+
params=self.qs.stringify(cast(Mapping[str, Any], params)) if params else None,
|
|
532
|
+
json=json_data,
|
|
533
|
+
files=options.files,
|
|
534
|
+
**kwargs,
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
def _serialize_multipartform(self, data: Mapping[object, object]) -> dict[str, object]:
|
|
538
|
+
items = self.qs.stringify_items(
|
|
539
|
+
# TODO: type ignore is required as stringify_items is well typed but we can't be
|
|
540
|
+
# well typed without heavy validation.
|
|
541
|
+
data, # type: ignore
|
|
542
|
+
array_format="brackets",
|
|
543
|
+
)
|
|
544
|
+
serialized: dict[str, object] = {}
|
|
545
|
+
for key, value in items:
|
|
546
|
+
if key in serialized:
|
|
547
|
+
raise ValueError(f"Duplicate key encountered: {key}; This behaviour is not supported")
|
|
548
|
+
serialized[key] = value
|
|
549
|
+
return serialized
|
|
550
|
+
|
|
551
|
+
def _process_response(
|
|
552
|
+
self,
|
|
553
|
+
*,
|
|
554
|
+
cast_to: Type[ResponseT],
|
|
555
|
+
options: FinalRequestOptions,
|
|
556
|
+
response: httpx.Response,
|
|
557
|
+
) -> ResponseT:
|
|
558
|
+
if cast_to is NoneType:
|
|
559
|
+
return cast(ResponseT, None)
|
|
560
|
+
|
|
561
|
+
if cast_to == str:
|
|
562
|
+
return cast(ResponseT, response.text)
|
|
563
|
+
|
|
564
|
+
origin = get_origin(cast_to) or cast_to
|
|
565
|
+
|
|
566
|
+
if inspect.isclass(origin) and issubclass(origin, httpx.Response):
|
|
567
|
+
# Because of the invariance of our ResponseT TypeVar, users can subclass httpx.Response
|
|
568
|
+
# and pass that class to our request functions. We cannot change the variance to be either
|
|
569
|
+
# covariant or contravariant as that makes our usage of ResponseT illegal. We could construct
|
|
570
|
+
# the response class ourselves but that is something that should be supported directly in httpx
|
|
571
|
+
# as it would be easy to incorrectly construct the Response object due to the multitude of arguments.
|
|
572
|
+
if cast_to != httpx.Response:
|
|
573
|
+
raise ValueError(f"Subclasses of httpx.Response cannot be passed to `cast_to`")
|
|
574
|
+
return cast(ResponseT, response)
|
|
575
|
+
|
|
576
|
+
# The check here is necessary as we are subverting the the type system
|
|
577
|
+
# with casts as the relationship between TypeVars and Types are very strict
|
|
578
|
+
# which means we must return *exactly* what was input or transform it in a
|
|
579
|
+
# way that retains the TypeVar state. As we cannot do that in this function
|
|
580
|
+
# then we have to resort to using `cast`. At the time of writing, we know this
|
|
581
|
+
# to be safe as we have handled all the types that could be bound to the
|
|
582
|
+
# `ResponseT` TypeVar, however if that TypeVar is ever updated in the future, then
|
|
583
|
+
# this function would become unsafe but a type checker would not report an error.
|
|
584
|
+
if (
|
|
585
|
+
cast_to is not UnknownResponse
|
|
586
|
+
and not origin is list
|
|
587
|
+
and not origin is dict
|
|
588
|
+
and not origin is Union
|
|
589
|
+
and not issubclass(origin, BaseModel)
|
|
590
|
+
):
|
|
591
|
+
raise RuntimeError(
|
|
592
|
+
f"Invalid state, expected {cast_to} to be a subclass type of {BaseModel}, {dict}, {list} or {Union}."
|
|
593
|
+
)
|
|
594
|
+
|
|
595
|
+
# split is required to handle cases where additional information is included
|
|
596
|
+
# in the response, e.g. application/json; charset=utf-8
|
|
597
|
+
content_type, *_ = response.headers.get("content-type").split(";")
|
|
598
|
+
if content_type != "application/json":
|
|
599
|
+
raise ValueError(
|
|
600
|
+
f"Expected Content-Type response header to be `application/json` but received {content_type} instead."
|
|
601
|
+
)
|
|
602
|
+
|
|
603
|
+
data = response.json()
|
|
604
|
+
return self._process_response_data(data=data, cast_to=cast_to, response=response)
|
|
605
|
+
|
|
606
|
+
def _process_response_data(
|
|
607
|
+
self,
|
|
608
|
+
*,
|
|
609
|
+
data: object,
|
|
610
|
+
cast_to: type[ResponseT],
|
|
611
|
+
response: httpx.Response,
|
|
612
|
+
) -> ResponseT:
|
|
613
|
+
if data is None:
|
|
614
|
+
return cast(ResponseT, None)
|
|
615
|
+
|
|
616
|
+
if cast_to is UnknownResponse:
|
|
617
|
+
return cast(ResponseT, data)
|
|
618
|
+
|
|
619
|
+
if inspect.isclass(cast_to) and issubclass(cast_to, ModelBuilderProtocol):
|
|
620
|
+
return cast(ResponseT, cast_to.build(response=response, data=data))
|
|
621
|
+
|
|
622
|
+
if self._strict_response_validation:
|
|
623
|
+
return cast(ResponseT, validate_type(type_=cast_to, value=data))
|
|
624
|
+
|
|
625
|
+
return cast(ResponseT, construct_type(type_=cast_to, value=data))
|
|
626
|
+
|
|
627
|
+
def _process_stream_line(self, contents: str) -> str:
|
|
628
|
+
"""Pre-process an indiviudal line from a streaming response"""
|
|
629
|
+
if contents == "data: [DONE]\n":
|
|
630
|
+
raise StopStreaming()
|
|
631
|
+
|
|
632
|
+
if contents.startswith("data: "):
|
|
633
|
+
return contents[6:]
|
|
634
|
+
|
|
635
|
+
return contents
|
|
636
|
+
|
|
637
|
+
@property
|
|
638
|
+
def qs(self) -> Querystring:
|
|
639
|
+
return Querystring()
|
|
640
|
+
|
|
641
|
+
@property
|
|
642
|
+
def custom_auth(self) -> httpx.Auth | None:
|
|
643
|
+
return None
|
|
644
|
+
|
|
645
|
+
@property
|
|
646
|
+
def auth_headers(self) -> dict[str, str]:
|
|
647
|
+
return {}
|
|
648
|
+
|
|
649
|
+
@property
|
|
650
|
+
def default_headers(self) -> dict[str, str | Omit]:
|
|
651
|
+
return {
|
|
652
|
+
"Content-Type": "application/json",
|
|
653
|
+
"User-Agent": self.user_agent,
|
|
654
|
+
**self.platform_headers(),
|
|
655
|
+
**self.auth_headers,
|
|
656
|
+
**self._custom_headers,
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
def _validate_headers(self, headers: Headers, custom_headers: Headers) -> None:
|
|
660
|
+
"""Validate the given default headers and custom headers.
|
|
661
|
+
|
|
662
|
+
Does nothing by default.
|
|
663
|
+
"""
|
|
664
|
+
return
|
|
665
|
+
|
|
666
|
+
@property
|
|
667
|
+
def user_agent(self) -> str:
|
|
668
|
+
return f"{self.__class__.__name__}/Python {self._version}"
|
|
669
|
+
|
|
670
|
+
@property
|
|
671
|
+
def base_url(self) -> URL:
|
|
672
|
+
return self._client.base_url
|
|
673
|
+
|
|
674
|
+
@lru_cache(maxsize=None)
|
|
675
|
+
def platform_headers(self) -> Dict[str, str]:
|
|
676
|
+
return {
|
|
677
|
+
"X-Stainless-Lang": "python",
|
|
678
|
+
"X-Stainless-Package-Version": self._version,
|
|
679
|
+
"X-Stainless-OS": str(get_platform()),
|
|
680
|
+
"X-Stainless-Arch": str(get_architecture()),
|
|
681
|
+
"X-Stainless-Runtime": platform.python_implementation(),
|
|
682
|
+
"X-Stainless-Runtime-Version": platform.python_version(),
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
def _calculate_retry_timeout(
|
|
686
|
+
self,
|
|
687
|
+
remaining_retries: int,
|
|
688
|
+
options: FinalRequestOptions,
|
|
689
|
+
response_headers: Optional[httpx.Headers] = None,
|
|
690
|
+
) -> float:
|
|
691
|
+
max_retries = options.get_max_retries(self.max_retries)
|
|
692
|
+
try:
|
|
693
|
+
# About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
|
|
694
|
+
#
|
|
695
|
+
# TODO: we may want to handle the case where the header is using the http-date syntax: "Retry-After:
|
|
696
|
+
# <http-date>". See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After#syntax for
|
|
697
|
+
# details.
|
|
698
|
+
retry_after = -1 if response_headers is None else int(response_headers.get("retry-after"))
|
|
699
|
+
except Exception:
|
|
700
|
+
retry_after = -1
|
|
701
|
+
|
|
702
|
+
# If the API asks us to wait a certain amount of time (and it's a reasonable amount), just do what it says.
|
|
703
|
+
if 0 < retry_after <= 60:
|
|
704
|
+
return retry_after
|
|
705
|
+
|
|
706
|
+
initial_retry_delay = 0.5
|
|
707
|
+
max_retry_delay = 2.0
|
|
708
|
+
nb_retries = max_retries - remaining_retries
|
|
709
|
+
|
|
710
|
+
# Apply exponential backoff, but not more than the max.
|
|
711
|
+
sleep_seconds = min(initial_retry_delay * pow(nb_retries - 1, 2), max_retry_delay)
|
|
712
|
+
|
|
713
|
+
# Apply some jitter, plus-or-minus half a second.
|
|
714
|
+
jitter = random() - 0.5
|
|
715
|
+
timeout = sleep_seconds + jitter
|
|
716
|
+
return timeout if timeout >= 0 else 0
|
|
717
|
+
|
|
718
|
+
def _should_retry(self, response: httpx.Response) -> bool:
|
|
719
|
+
# Note: this is not a standard header
|
|
720
|
+
should_retry_header = response.headers.get("x-should-retry")
|
|
721
|
+
|
|
722
|
+
# If the server explicitly says whether or not to retry, obey.
|
|
723
|
+
if should_retry_header == "true":
|
|
724
|
+
return True
|
|
725
|
+
if should_retry_header == "false":
|
|
726
|
+
return False
|
|
727
|
+
|
|
728
|
+
# Retry on lock timeouts.
|
|
729
|
+
if response.status_code == 409:
|
|
730
|
+
return True
|
|
731
|
+
|
|
732
|
+
# Retry on rate limits.
|
|
733
|
+
if response.status_code == 429:
|
|
734
|
+
return True
|
|
735
|
+
|
|
736
|
+
# Retry internal errors.
|
|
737
|
+
if response.status_code >= 500:
|
|
738
|
+
return True
|
|
739
|
+
|
|
740
|
+
return False
|
|
741
|
+
|
|
742
|
+
def _idempotency_key(self) -> str:
|
|
743
|
+
return f"stainless-python-retry-{uuid.uuid4()}"
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
class SyncAPIClient(BaseClient):
|
|
747
|
+
_client: httpx.Client
|
|
748
|
+
|
|
749
|
+
def __init__(
|
|
750
|
+
self,
|
|
751
|
+
*,
|
|
752
|
+
version: str,
|
|
753
|
+
base_url: str,
|
|
754
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
755
|
+
timeout: float | Timeout | None = DEFAULT_TIMEOUT,
|
|
756
|
+
transport: Transport | None = None,
|
|
757
|
+
proxies: ProxiesTypes | None = None,
|
|
758
|
+
limits: Limits | None = DEFAULT_LIMITS,
|
|
759
|
+
custom_headers: Mapping[str, str] | None = None,
|
|
760
|
+
custom_query: Mapping[str, object] | None = None,
|
|
761
|
+
_strict_response_validation: bool,
|
|
762
|
+
) -> None:
|
|
763
|
+
limits = limits or DEFAULT_LIMITS
|
|
764
|
+
super().__init__(
|
|
765
|
+
version=version,
|
|
766
|
+
limits=limits,
|
|
767
|
+
timeout=timeout,
|
|
768
|
+
max_retries=max_retries,
|
|
769
|
+
custom_query=custom_query,
|
|
770
|
+
custom_headers=custom_headers,
|
|
771
|
+
_strict_response_validation=_strict_response_validation,
|
|
772
|
+
)
|
|
773
|
+
self._client = httpx.Client(
|
|
774
|
+
base_url=base_url,
|
|
775
|
+
timeout=timeout,
|
|
776
|
+
proxies=proxies, # type: ignore
|
|
777
|
+
transport=transport, # type: ignore
|
|
778
|
+
limits=limits,
|
|
779
|
+
headers={"Accept": "application/json"},
|
|
780
|
+
)
|
|
781
|
+
|
|
782
|
+
@overload
|
|
783
|
+
def request(
|
|
784
|
+
self,
|
|
785
|
+
cast_to: Type[ResponseT],
|
|
786
|
+
options: FinalRequestOptions,
|
|
787
|
+
remaining_retries: Optional[int] = None,
|
|
788
|
+
*,
|
|
789
|
+
stream: Literal[True],
|
|
790
|
+
) -> Stream[ResponseT]:
|
|
791
|
+
...
|
|
792
|
+
|
|
793
|
+
@overload
|
|
794
|
+
def request(
|
|
795
|
+
self,
|
|
796
|
+
cast_to: Type[ResponseT],
|
|
797
|
+
options: FinalRequestOptions,
|
|
798
|
+
remaining_retries: Optional[int] = None,
|
|
799
|
+
*,
|
|
800
|
+
stream: Literal[False] = False,
|
|
801
|
+
) -> ResponseT:
|
|
802
|
+
...
|
|
803
|
+
|
|
804
|
+
@overload
|
|
805
|
+
def request(
|
|
806
|
+
self,
|
|
807
|
+
cast_to: Type[ResponseT],
|
|
808
|
+
options: FinalRequestOptions,
|
|
809
|
+
remaining_retries: Optional[int] = None,
|
|
810
|
+
*,
|
|
811
|
+
stream: bool = False,
|
|
812
|
+
) -> ResponseT | Stream[ResponseT]:
|
|
813
|
+
...
|
|
814
|
+
|
|
815
|
+
def request(
|
|
816
|
+
self,
|
|
817
|
+
cast_to: Type[ResponseT],
|
|
818
|
+
options: FinalRequestOptions,
|
|
819
|
+
remaining_retries: Optional[int] = None,
|
|
820
|
+
*,
|
|
821
|
+
stream: bool = False,
|
|
822
|
+
) -> ResponseT | Stream[ResponseT]:
|
|
823
|
+
return self._request(
|
|
824
|
+
cast_to=cast_to,
|
|
825
|
+
options=options,
|
|
826
|
+
stream=stream,
|
|
827
|
+
remaining_retries=remaining_retries,
|
|
828
|
+
)
|
|
829
|
+
|
|
830
|
+
def _request(
|
|
831
|
+
self,
|
|
832
|
+
*,
|
|
833
|
+
cast_to: Type[ResponseT],
|
|
834
|
+
options: FinalRequestOptions,
|
|
835
|
+
remaining_retries: int | None,
|
|
836
|
+
stream: bool,
|
|
837
|
+
) -> ResponseT | Stream[ResponseT]:
|
|
838
|
+
retries = self._remaining_retries(remaining_retries, options)
|
|
839
|
+
request = self._build_request(options)
|
|
840
|
+
|
|
841
|
+
try:
|
|
842
|
+
response = self._client.send(request, auth=self.custom_auth, stream=stream)
|
|
843
|
+
response.raise_for_status()
|
|
844
|
+
except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
|
|
845
|
+
if retries > 0 and self._should_retry(err.response):
|
|
846
|
+
return self._retry_request(options, cast_to, retries, err.response.headers, stream=stream)
|
|
847
|
+
|
|
848
|
+
# If the response is streamed then we need to explicitly read the response
|
|
849
|
+
# to completion before attempting to access the response text.
|
|
850
|
+
err.response.read()
|
|
851
|
+
raise self._make_status_error_from_response(request, err.response) from None
|
|
852
|
+
except httpx.TimeoutException as err:
|
|
853
|
+
if retries > 0:
|
|
854
|
+
return self._retry_request(options, cast_to, retries, stream=stream)
|
|
855
|
+
raise APITimeoutError(request=request) from err
|
|
856
|
+
except Exception as err:
|
|
857
|
+
if retries > 0:
|
|
858
|
+
return self._retry_request(options, cast_to, retries, stream=stream)
|
|
859
|
+
raise APIConnectionError(request=request) from err
|
|
860
|
+
|
|
861
|
+
if stream:
|
|
862
|
+
return Stream(cast_to=cast_to, response=response, client=self)
|
|
863
|
+
|
|
864
|
+
try:
|
|
865
|
+
rsp = self._process_response(cast_to=cast_to, options=options, response=response)
|
|
866
|
+
except pydantic.ValidationError as err:
|
|
867
|
+
raise APIResponseValidationError(request=request, response=response) from err
|
|
868
|
+
|
|
869
|
+
return rsp
|
|
870
|
+
|
|
871
|
+
def _retry_request(
|
|
872
|
+
self,
|
|
873
|
+
options: FinalRequestOptions,
|
|
874
|
+
cast_to: Type[ResponseT],
|
|
875
|
+
remaining_retries: int,
|
|
876
|
+
response_headers: Optional[httpx.Headers] = None,
|
|
877
|
+
*,
|
|
878
|
+
stream: bool,
|
|
879
|
+
) -> ResponseT | Stream[ResponseT]:
|
|
880
|
+
remaining = remaining_retries - 1
|
|
881
|
+
timeout = self._calculate_retry_timeout(remaining, options, response_headers)
|
|
882
|
+
|
|
883
|
+
# In a synchronous context we are blocking the entire thread. Up to the library user to run the client in a
|
|
884
|
+
# different thread if necessary.
|
|
885
|
+
time.sleep(timeout)
|
|
886
|
+
|
|
887
|
+
return self._request(
|
|
888
|
+
options=options,
|
|
889
|
+
cast_to=cast_to,
|
|
890
|
+
remaining_retries=remaining,
|
|
891
|
+
stream=stream,
|
|
892
|
+
)
|
|
893
|
+
|
|
894
|
+
def _request_api_list(
|
|
895
|
+
self,
|
|
896
|
+
model: Type[ModelT],
|
|
897
|
+
page: Type[SyncPageT],
|
|
898
|
+
options: FinalRequestOptions,
|
|
899
|
+
) -> SyncPageT:
|
|
900
|
+
resp = cast(SyncPageT, self.request(page, options, stream=False))
|
|
901
|
+
resp._set_private_attributes( # pyright: ignore[reportPrivateUsage]
|
|
902
|
+
client=self,
|
|
903
|
+
model=model,
|
|
904
|
+
options=options,
|
|
905
|
+
)
|
|
906
|
+
return resp
|
|
907
|
+
|
|
908
|
+
def get(
|
|
909
|
+
self,
|
|
910
|
+
path: str,
|
|
911
|
+
*,
|
|
912
|
+
cast_to: Type[ResponseT],
|
|
913
|
+
options: RequestOptions = {},
|
|
914
|
+
) -> ResponseT:
|
|
915
|
+
opts = FinalRequestOptions.construct(method="get", url=path, **options)
|
|
916
|
+
# cast is required because mypy complains about returning Any even though
|
|
917
|
+
# it understands the type variables
|
|
918
|
+
return cast(ResponseT, self.request(cast_to, opts, stream=False))
|
|
919
|
+
|
|
920
|
+
@overload
|
|
921
|
+
def post(
|
|
922
|
+
self,
|
|
923
|
+
path: str,
|
|
924
|
+
*,
|
|
925
|
+
cast_to: Type[ResponseT],
|
|
926
|
+
body: Body | None = None,
|
|
927
|
+
options: RequestOptions = {},
|
|
928
|
+
files: RequestFiles | None = None,
|
|
929
|
+
stream: Literal[False] = False,
|
|
930
|
+
) -> ResponseT:
|
|
931
|
+
...
|
|
932
|
+
|
|
933
|
+
@overload
|
|
934
|
+
def post(
|
|
935
|
+
self,
|
|
936
|
+
path: str,
|
|
937
|
+
*,
|
|
938
|
+
cast_to: Type[ResponseT],
|
|
939
|
+
body: Body | None = None,
|
|
940
|
+
options: RequestOptions = {},
|
|
941
|
+
files: RequestFiles | None = None,
|
|
942
|
+
stream: Literal[True],
|
|
943
|
+
) -> Stream[ResponseT]:
|
|
944
|
+
...
|
|
945
|
+
|
|
946
|
+
@overload
|
|
947
|
+
def post(
|
|
948
|
+
self,
|
|
949
|
+
path: str,
|
|
950
|
+
*,
|
|
951
|
+
cast_to: Type[ResponseT],
|
|
952
|
+
body: Body | None = None,
|
|
953
|
+
options: RequestOptions = {},
|
|
954
|
+
files: RequestFiles | None = None,
|
|
955
|
+
stream: bool,
|
|
956
|
+
) -> ResponseT | Stream[ResponseT]:
|
|
957
|
+
...
|
|
958
|
+
|
|
959
|
+
def post(
|
|
960
|
+
self,
|
|
961
|
+
path: str,
|
|
962
|
+
*,
|
|
963
|
+
cast_to: Type[ResponseT],
|
|
964
|
+
body: Body | None = None,
|
|
965
|
+
options: RequestOptions = {},
|
|
966
|
+
files: RequestFiles | None = None,
|
|
967
|
+
stream: bool = False,
|
|
968
|
+
) -> ResponseT | Stream[ResponseT]:
|
|
969
|
+
opts = FinalRequestOptions.construct(method="post", url=path, json_data=body, files=files, **options)
|
|
970
|
+
return cast(ResponseT, self.request(cast_to, opts, stream=stream))
|
|
971
|
+
|
|
972
|
+
def patch(
|
|
973
|
+
self,
|
|
974
|
+
path: str,
|
|
975
|
+
*,
|
|
976
|
+
cast_to: Type[ResponseT],
|
|
977
|
+
body: Body | None = None,
|
|
978
|
+
options: RequestOptions = {},
|
|
979
|
+
) -> ResponseT:
|
|
980
|
+
opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options)
|
|
981
|
+
return cast(ResponseT, self.request(cast_to, opts))
|
|
982
|
+
|
|
983
|
+
def put(
|
|
984
|
+
self,
|
|
985
|
+
path: str,
|
|
986
|
+
*,
|
|
987
|
+
cast_to: Type[ResponseT],
|
|
988
|
+
body: Body | None = None,
|
|
989
|
+
files: RequestFiles | None = None,
|
|
990
|
+
options: RequestOptions = {},
|
|
991
|
+
) -> ResponseT:
|
|
992
|
+
opts = FinalRequestOptions.construct(method="put", url=path, json_data=body, files=files, **options)
|
|
993
|
+
return cast(ResponseT, self.request(cast_to, opts))
|
|
994
|
+
|
|
995
|
+
def delete(
|
|
996
|
+
self,
|
|
997
|
+
path: str,
|
|
998
|
+
*,
|
|
999
|
+
cast_to: Type[ResponseT],
|
|
1000
|
+
body: Body | None = None,
|
|
1001
|
+
options: RequestOptions = {},
|
|
1002
|
+
) -> ResponseT:
|
|
1003
|
+
opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
|
|
1004
|
+
return cast(ResponseT, self.request(cast_to, opts))
|
|
1005
|
+
|
|
1006
|
+
def get_api_list(
|
|
1007
|
+
self,
|
|
1008
|
+
path: str,
|
|
1009
|
+
*,
|
|
1010
|
+
model: Type[ModelT],
|
|
1011
|
+
page: Type[SyncPageT],
|
|
1012
|
+
body: Body | None = None,
|
|
1013
|
+
options: RequestOptions = {},
|
|
1014
|
+
method: str = "get",
|
|
1015
|
+
) -> SyncPageT:
|
|
1016
|
+
opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options)
|
|
1017
|
+
return self._request_api_list(model, page, opts)
|
|
1018
|
+
|
|
1019
|
+
|
|
1020
|
+
class AsyncAPIClient(BaseClient):
|
|
1021
|
+
_client: httpx.AsyncClient
|
|
1022
|
+
|
|
1023
|
+
def __init__(
|
|
1024
|
+
self,
|
|
1025
|
+
*,
|
|
1026
|
+
version: str,
|
|
1027
|
+
base_url: str,
|
|
1028
|
+
_strict_response_validation: bool,
|
|
1029
|
+
max_retries: int = DEFAULT_MAX_RETRIES,
|
|
1030
|
+
timeout: float | Timeout | None = DEFAULT_TIMEOUT,
|
|
1031
|
+
transport: Transport | None = None,
|
|
1032
|
+
proxies: ProxiesTypes | None = None,
|
|
1033
|
+
limits: Limits | None = DEFAULT_LIMITS,
|
|
1034
|
+
custom_headers: Mapping[str, str] | None = None,
|
|
1035
|
+
custom_query: Mapping[str, object] | None = None,
|
|
1036
|
+
) -> None:
|
|
1037
|
+
limits = limits or DEFAULT_LIMITS
|
|
1038
|
+
super().__init__(
|
|
1039
|
+
version=version,
|
|
1040
|
+
limits=limits,
|
|
1041
|
+
timeout=timeout,
|
|
1042
|
+
max_retries=max_retries,
|
|
1043
|
+
custom_query=custom_query,
|
|
1044
|
+
custom_headers=custom_headers,
|
|
1045
|
+
_strict_response_validation=_strict_response_validation,
|
|
1046
|
+
)
|
|
1047
|
+
self._client = httpx.AsyncClient(
|
|
1048
|
+
base_url=base_url,
|
|
1049
|
+
timeout=timeout,
|
|
1050
|
+
proxies=proxies, # type: ignore
|
|
1051
|
+
transport=transport, # type: ignore
|
|
1052
|
+
limits=limits,
|
|
1053
|
+
headers={"Accept": "application/json"},
|
|
1054
|
+
)
|
|
1055
|
+
|
|
1056
|
+
@overload
|
|
1057
|
+
async def request(
|
|
1058
|
+
self,
|
|
1059
|
+
cast_to: Type[ResponseT],
|
|
1060
|
+
options: FinalRequestOptions,
|
|
1061
|
+
*,
|
|
1062
|
+
stream: Literal[False] = False,
|
|
1063
|
+
remaining_retries: Optional[int] = None,
|
|
1064
|
+
) -> ResponseT:
|
|
1065
|
+
...
|
|
1066
|
+
|
|
1067
|
+
@overload
|
|
1068
|
+
async def request(
|
|
1069
|
+
self,
|
|
1070
|
+
cast_to: Type[ResponseT],
|
|
1071
|
+
options: FinalRequestOptions,
|
|
1072
|
+
*,
|
|
1073
|
+
stream: Literal[True],
|
|
1074
|
+
remaining_retries: Optional[int] = None,
|
|
1075
|
+
) -> AsyncStream[ResponseT]:
|
|
1076
|
+
...
|
|
1077
|
+
|
|
1078
|
+
@overload
|
|
1079
|
+
async def request(
|
|
1080
|
+
self,
|
|
1081
|
+
cast_to: Type[ResponseT],
|
|
1082
|
+
options: FinalRequestOptions,
|
|
1083
|
+
*,
|
|
1084
|
+
stream: bool,
|
|
1085
|
+
remaining_retries: Optional[int] = None,
|
|
1086
|
+
) -> ResponseT | AsyncStream[ResponseT]:
|
|
1087
|
+
...
|
|
1088
|
+
|
|
1089
|
+
async def request(
|
|
1090
|
+
self,
|
|
1091
|
+
cast_to: Type[ResponseT],
|
|
1092
|
+
options: FinalRequestOptions,
|
|
1093
|
+
*,
|
|
1094
|
+
stream: bool = False,
|
|
1095
|
+
remaining_retries: Optional[int] = None,
|
|
1096
|
+
) -> ResponseT | AsyncStream[ResponseT]:
|
|
1097
|
+
return await self._request(
|
|
1098
|
+
cast_to=cast_to,
|
|
1099
|
+
options=options,
|
|
1100
|
+
stream=stream,
|
|
1101
|
+
remaining_retries=remaining_retries,
|
|
1102
|
+
)
|
|
1103
|
+
|
|
1104
|
+
async def _request(
|
|
1105
|
+
self,
|
|
1106
|
+
cast_to: Type[ResponseT],
|
|
1107
|
+
options: FinalRequestOptions,
|
|
1108
|
+
*,
|
|
1109
|
+
stream: bool,
|
|
1110
|
+
remaining_retries: int | None,
|
|
1111
|
+
) -> ResponseT | AsyncStream[ResponseT]:
|
|
1112
|
+
retries = self._remaining_retries(remaining_retries, options)
|
|
1113
|
+
request = self._build_request(options)
|
|
1114
|
+
|
|
1115
|
+
try:
|
|
1116
|
+
response = await self._client.send(request, auth=self.custom_auth, stream=stream)
|
|
1117
|
+
response.raise_for_status()
|
|
1118
|
+
except httpx.HTTPStatusError as err: # thrown on 4xx and 5xx status code
|
|
1119
|
+
if retries > 0 and self._should_retry(err.response):
|
|
1120
|
+
return await self._retry_request(options, cast_to, retries, err.response.headers, stream=stream)
|
|
1121
|
+
|
|
1122
|
+
# If the response is streamed then we need to explicitly read the response
|
|
1123
|
+
# to completion before attempting to access the response text.
|
|
1124
|
+
await err.response.aread()
|
|
1125
|
+
raise self._make_status_error_from_response(request, err.response) from None
|
|
1126
|
+
except httpx.ConnectTimeout as err:
|
|
1127
|
+
if retries > 0:
|
|
1128
|
+
return await self._retry_request(options, cast_to, retries, stream=stream)
|
|
1129
|
+
raise APITimeoutError(request=request) from err
|
|
1130
|
+
except httpx.ReadTimeout as err:
|
|
1131
|
+
# We explicitly do not retry on ReadTimeout errors as this means
|
|
1132
|
+
# that the server processing the request has taken 60 seconds
|
|
1133
|
+
# (our default timeout). This likely indicates that something
|
|
1134
|
+
# is not working as expected on the server side.
|
|
1135
|
+
raise
|
|
1136
|
+
except httpx.TimeoutException as err:
|
|
1137
|
+
if retries > 0:
|
|
1138
|
+
return await self._retry_request(options, cast_to, retries, stream=stream)
|
|
1139
|
+
raise APITimeoutError(request=request) from err
|
|
1140
|
+
except Exception as err:
|
|
1141
|
+
if retries > 0:
|
|
1142
|
+
return await self._retry_request(options, cast_to, retries, stream=stream)
|
|
1143
|
+
raise APIConnectionError(request=request) from err
|
|
1144
|
+
|
|
1145
|
+
if stream:
|
|
1146
|
+
return AsyncStream(cast_to=cast_to, response=response, client=self)
|
|
1147
|
+
|
|
1148
|
+
try:
|
|
1149
|
+
rsp = self._process_response(cast_to=cast_to, options=options, response=response)
|
|
1150
|
+
except pydantic.ValidationError as err:
|
|
1151
|
+
raise APIResponseValidationError(request=request, response=response) from err
|
|
1152
|
+
|
|
1153
|
+
return rsp
|
|
1154
|
+
|
|
1155
|
+
async def _retry_request(
|
|
1156
|
+
self,
|
|
1157
|
+
options: FinalRequestOptions,
|
|
1158
|
+
cast_to: Type[ResponseT],
|
|
1159
|
+
remaining_retries: int,
|
|
1160
|
+
response_headers: Optional[httpx.Headers] = None,
|
|
1161
|
+
*,
|
|
1162
|
+
stream: bool,
|
|
1163
|
+
) -> ResponseT | AsyncStream[ResponseT]:
|
|
1164
|
+
remaining = remaining_retries - 1
|
|
1165
|
+
timeout = self._calculate_retry_timeout(remaining, options, response_headers)
|
|
1166
|
+
|
|
1167
|
+
await anyio.sleep(timeout)
|
|
1168
|
+
|
|
1169
|
+
return await self._request(
|
|
1170
|
+
options=options,
|
|
1171
|
+
cast_to=cast_to,
|
|
1172
|
+
remaining_retries=remaining,
|
|
1173
|
+
stream=stream,
|
|
1174
|
+
)
|
|
1175
|
+
|
|
1176
|
+
def _request_api_list(
|
|
1177
|
+
self,
|
|
1178
|
+
model: Type[ModelT],
|
|
1179
|
+
page: Type[AsyncPageT],
|
|
1180
|
+
options: FinalRequestOptions,
|
|
1181
|
+
) -> AsyncPaginator[ModelT, AsyncPageT]:
|
|
1182
|
+
return AsyncPaginator(client=self, options=options, page_cls=page, model=model)
|
|
1183
|
+
|
|
1184
|
+
async def get(
|
|
1185
|
+
self,
|
|
1186
|
+
path: str,
|
|
1187
|
+
*,
|
|
1188
|
+
cast_to: Type[ResponseT],
|
|
1189
|
+
options: RequestOptions = {},
|
|
1190
|
+
) -> ResponseT:
|
|
1191
|
+
opts = FinalRequestOptions.construct(method="get", url=path, **options)
|
|
1192
|
+
return await self.request(cast_to, opts)
|
|
1193
|
+
|
|
1194
|
+
@overload
|
|
1195
|
+
async def post(
|
|
1196
|
+
self,
|
|
1197
|
+
path: str,
|
|
1198
|
+
*,
|
|
1199
|
+
cast_to: Type[ResponseT],
|
|
1200
|
+
body: Body | None = None,
|
|
1201
|
+
files: RequestFiles | None = None,
|
|
1202
|
+
options: RequestOptions = {},
|
|
1203
|
+
stream: Literal[False] = False,
|
|
1204
|
+
) -> ResponseT:
|
|
1205
|
+
...
|
|
1206
|
+
|
|
1207
|
+
@overload
|
|
1208
|
+
async def post(
|
|
1209
|
+
self,
|
|
1210
|
+
path: str,
|
|
1211
|
+
*,
|
|
1212
|
+
cast_to: Type[ResponseT],
|
|
1213
|
+
body: Body | None = None,
|
|
1214
|
+
files: RequestFiles | None = None,
|
|
1215
|
+
options: RequestOptions = {},
|
|
1216
|
+
stream: Literal[True],
|
|
1217
|
+
) -> AsyncStream[ResponseT]:
|
|
1218
|
+
...
|
|
1219
|
+
|
|
1220
|
+
@overload
|
|
1221
|
+
async def post(
|
|
1222
|
+
self,
|
|
1223
|
+
path: str,
|
|
1224
|
+
*,
|
|
1225
|
+
cast_to: Type[ResponseT],
|
|
1226
|
+
body: Body | None = None,
|
|
1227
|
+
files: RequestFiles | None = None,
|
|
1228
|
+
options: RequestOptions = {},
|
|
1229
|
+
stream: bool,
|
|
1230
|
+
) -> ResponseT | AsyncStream[ResponseT]:
|
|
1231
|
+
...
|
|
1232
|
+
|
|
1233
|
+
async def post(
|
|
1234
|
+
self,
|
|
1235
|
+
path: str,
|
|
1236
|
+
*,
|
|
1237
|
+
cast_to: Type[ResponseT],
|
|
1238
|
+
body: Body | None = None,
|
|
1239
|
+
files: RequestFiles | None = None,
|
|
1240
|
+
options: RequestOptions = {},
|
|
1241
|
+
stream: bool = False,
|
|
1242
|
+
) -> ResponseT | AsyncStream[ResponseT]:
|
|
1243
|
+
opts = FinalRequestOptions.construct(method="post", url=path, json_data=body, files=files, **options)
|
|
1244
|
+
return await self.request(cast_to, opts, stream=stream)
|
|
1245
|
+
|
|
1246
|
+
async def patch(
|
|
1247
|
+
self,
|
|
1248
|
+
path: str,
|
|
1249
|
+
*,
|
|
1250
|
+
cast_to: Type[ResponseT],
|
|
1251
|
+
body: Body | None = None,
|
|
1252
|
+
options: RequestOptions = {},
|
|
1253
|
+
) -> ResponseT:
|
|
1254
|
+
opts = FinalRequestOptions.construct(method="patch", url=path, json_data=body, **options)
|
|
1255
|
+
return await self.request(cast_to, opts)
|
|
1256
|
+
|
|
1257
|
+
async def put(
|
|
1258
|
+
self,
|
|
1259
|
+
path: str,
|
|
1260
|
+
*,
|
|
1261
|
+
cast_to: Type[ResponseT],
|
|
1262
|
+
body: Body | None = None,
|
|
1263
|
+
files: RequestFiles | None = None,
|
|
1264
|
+
options: RequestOptions = {},
|
|
1265
|
+
) -> ResponseT:
|
|
1266
|
+
opts = FinalRequestOptions.construct(method="put", url=path, json_data=body, files=files, **options)
|
|
1267
|
+
return await self.request(cast_to, opts)
|
|
1268
|
+
|
|
1269
|
+
async def delete(
|
|
1270
|
+
self,
|
|
1271
|
+
path: str,
|
|
1272
|
+
*,
|
|
1273
|
+
cast_to: Type[ResponseT],
|
|
1274
|
+
body: Body | None = None,
|
|
1275
|
+
options: RequestOptions = {},
|
|
1276
|
+
) -> ResponseT:
|
|
1277
|
+
opts = FinalRequestOptions.construct(method="delete", url=path, json_data=body, **options)
|
|
1278
|
+
return await self.request(cast_to, opts)
|
|
1279
|
+
|
|
1280
|
+
def get_api_list(
|
|
1281
|
+
self,
|
|
1282
|
+
path: str,
|
|
1283
|
+
*,
|
|
1284
|
+
# TODO: support paginating `str`
|
|
1285
|
+
model: Type[ModelT],
|
|
1286
|
+
page: Type[AsyncPageT],
|
|
1287
|
+
body: Body | None = None,
|
|
1288
|
+
options: RequestOptions = {},
|
|
1289
|
+
method: str = "get",
|
|
1290
|
+
) -> AsyncPaginator[ModelT, AsyncPageT]:
|
|
1291
|
+
opts = FinalRequestOptions.construct(method=method, url=path, json_data=body, **options)
|
|
1292
|
+
return self._request_api_list(model, page, opts)
|
|
1293
|
+
|
|
1294
|
+
|
|
1295
|
+
def make_request_options(
|
|
1296
|
+
*,
|
|
1297
|
+
query: Query | None = None,
|
|
1298
|
+
extra_headers: Headers | None = None,
|
|
1299
|
+
extra_query: Query | None = None,
|
|
1300
|
+
extra_body: Body | None = None,
|
|
1301
|
+
idempotency_key: str | None = None,
|
|
1302
|
+
timeout: float | None | NotGiven = NOT_GIVEN,
|
|
1303
|
+
) -> RequestOptions:
|
|
1304
|
+
"""Create a dict of type RequestOptions without keys of NotGiven values."""
|
|
1305
|
+
options: RequestOptions = {}
|
|
1306
|
+
if extra_headers is not None:
|
|
1307
|
+
options["headers"] = extra_headers
|
|
1308
|
+
|
|
1309
|
+
if extra_body is not None:
|
|
1310
|
+
options["extra_json"] = cast(AnyMapping, extra_body)
|
|
1311
|
+
|
|
1312
|
+
if query is not None:
|
|
1313
|
+
options["params"] = query
|
|
1314
|
+
|
|
1315
|
+
if extra_query is not None:
|
|
1316
|
+
options["params"] = {**options.get("params", {}), **extra_query}
|
|
1317
|
+
|
|
1318
|
+
if not isinstance(timeout, NotGiven):
|
|
1319
|
+
options["timeout"] = timeout
|
|
1320
|
+
|
|
1321
|
+
if idempotency_key is not None:
|
|
1322
|
+
options["idempotency_key"] = idempotency_key
|
|
1323
|
+
|
|
1324
|
+
return options
|
|
1325
|
+
|
|
1326
|
+
|
|
1327
|
+
class OtherPlatform:
|
|
1328
|
+
def __init__(self, name: str) -> None:
|
|
1329
|
+
self.name = name
|
|
1330
|
+
|
|
1331
|
+
def __str__(self) -> str:
|
|
1332
|
+
return f"Other:{self.name}"
|
|
1333
|
+
|
|
1334
|
+
|
|
1335
|
+
Platform = Union[
|
|
1336
|
+
OtherPlatform,
|
|
1337
|
+
Literal[
|
|
1338
|
+
"MacOS",
|
|
1339
|
+
"Linux",
|
|
1340
|
+
"Windows",
|
|
1341
|
+
"FreeBSD",
|
|
1342
|
+
"OpenBSD",
|
|
1343
|
+
"iOS",
|
|
1344
|
+
"Android",
|
|
1345
|
+
"Unknown",
|
|
1346
|
+
],
|
|
1347
|
+
]
|
|
1348
|
+
|
|
1349
|
+
|
|
1350
|
+
def get_platform() -> Platform:
|
|
1351
|
+
system = platform.system().lower()
|
|
1352
|
+
platform_name = platform.platform().lower()
|
|
1353
|
+
if "iphone" in platform_name or "ipad" in platform_name:
|
|
1354
|
+
# Tested using Python3IDE on an iPhone 11 and Pythonista on an iPad 7
|
|
1355
|
+
# system is Darwin and platform_name is a string like:
|
|
1356
|
+
# - Darwin-21.6.0-iPhone12,1-64bit
|
|
1357
|
+
# - Darwin-21.6.0-iPad7,11-64bit
|
|
1358
|
+
return "iOS"
|
|
1359
|
+
|
|
1360
|
+
if system == "darwin":
|
|
1361
|
+
return "MacOS"
|
|
1362
|
+
|
|
1363
|
+
if system == "windows":
|
|
1364
|
+
return "Windows"
|
|
1365
|
+
|
|
1366
|
+
if "android" in platform_name:
|
|
1367
|
+
# Tested using Pydroid 3
|
|
1368
|
+
# system is Linux and platform_name is a string like 'Linux-5.10.81-android12-9-00001-geba40aecb3b7-ab8534902-aarch64-with-libc'
|
|
1369
|
+
return "Android"
|
|
1370
|
+
|
|
1371
|
+
if system == "linux":
|
|
1372
|
+
# https://distro.readthedocs.io/en/latest/#distro.id
|
|
1373
|
+
distro_id = distro.id()
|
|
1374
|
+
if distro_id == "freebsd":
|
|
1375
|
+
return "FreeBSD"
|
|
1376
|
+
|
|
1377
|
+
if distro_id == "openbsd":
|
|
1378
|
+
return "OpenBSD"
|
|
1379
|
+
|
|
1380
|
+
return "Linux"
|
|
1381
|
+
|
|
1382
|
+
if platform_name:
|
|
1383
|
+
return OtherPlatform(platform_name)
|
|
1384
|
+
|
|
1385
|
+
return "Unknown"
|
|
1386
|
+
|
|
1387
|
+
|
|
1388
|
+
class OtherArch:
|
|
1389
|
+
def __init__(self, name: str) -> None:
|
|
1390
|
+
self.name = name
|
|
1391
|
+
|
|
1392
|
+
def __str__(self) -> str:
|
|
1393
|
+
return f"other:{self.name}"
|
|
1394
|
+
|
|
1395
|
+
|
|
1396
|
+
Arch = Union[OtherArch, Literal["x32", "x64", "arm", "arm64", "unknown"]]
|
|
1397
|
+
|
|
1398
|
+
|
|
1399
|
+
def get_architecture() -> Arch:
|
|
1400
|
+
python_bitness, _ = platform.architecture()
|
|
1401
|
+
machine = platform.machine().lower()
|
|
1402
|
+
if machine in ("arm64", "aarch64"):
|
|
1403
|
+
return "arm64"
|
|
1404
|
+
|
|
1405
|
+
# TODO: untested
|
|
1406
|
+
if machine == "arm":
|
|
1407
|
+
return "arm"
|
|
1408
|
+
|
|
1409
|
+
if machine == "x86_64":
|
|
1410
|
+
return "x64"
|
|
1411
|
+
|
|
1412
|
+
# TODO: untested
|
|
1413
|
+
if python_bitness == "32bit":
|
|
1414
|
+
return "x32"
|
|
1415
|
+
|
|
1416
|
+
if machine:
|
|
1417
|
+
return OtherArch(machine)
|
|
1418
|
+
|
|
1419
|
+
return "unknown"
|
|
1420
|
+
|
|
1421
|
+
|
|
1422
|
+
def _merge_mappings(
|
|
1423
|
+
obj1: Mapping[_T_co, Union[_T, Omit]],
|
|
1424
|
+
obj2: Mapping[_T_co, Union[_T, Omit]],
|
|
1425
|
+
) -> Dict[_T_co, _T]:
|
|
1426
|
+
"""Merge two mappings of the same type, removing any values that are instances of `Omit`.
|
|
1427
|
+
|
|
1428
|
+
In cases with duplicate keys the second mapping takes precedence.
|
|
1429
|
+
"""
|
|
1430
|
+
merged = {**obj1, **obj2}
|
|
1431
|
+
return {key: value for key, value in merged.items() if not isinstance(value, Omit)}
|